发布 订阅 消息系统(一)

1.从监听与发布说起

我们写js代码的时候都知道有这样的事件:我们注册一个click方法 ,此时我们就为这个按钮添加了“监听”,基于“点击”事件的监听。以此来实现点击按钮提交表单数据的目的,在这里,我们通过点(发)击(布)这个动作,让系统知道:哦,我要提交这些表单。   这里的click方法,就是我们所要说的 “发布”。
 

2.发布消息之后发生了什么

当我发布登录消息的时候,就有很多模块来响应,比如我登录博客,页面的头部展示我的私人信息,首页展示我的博客内容等。就会有很多模块用各自方法对这个信息进行处理,那么这些方法存放在哪里呢?我可以创建一个对象
<script type="text/javascript">
    var callback = {};
</script>
 
这些方法有很多,而每个方法又对应很多回调函数,我需要对这些方法数据进行梳理:
<script type="text/javascript">
	var callback = {
		login: [
			function(){},//head回调
			function(){}//内容回调
		],
		req: [
			function(){},
			function(){}
		]
		...
	}
</script>
比如:我发出 login 消息,就要找到login对应的回调方法,去处理login产生的结果,将结果存储在callback里。
 

3.一般的消息处理方法

比如有一个登录框,我登录成功后页面顶部改变,内容区域显示我的个人信息,一般我们可以这样写:
 
<script type="text/javascript">
	
	(function() {
			$.ajax({
				url:'http://blog.csdn.net/lihchweb',
				data:{},
				success: function() {
				//成功了
				$("#head name").html("lihouchun");
				$("#content").html(infos);
				//....
				//....
				}
			})
		})();
</script>

 
 
这种简单粗暴,哪个地方需要响应,他就去修改哪个地方,处理问题的方法很集中,耦合性比较高。试想一下如果有很多需要响应的部分呢?
 
 
这显然不是我们想要的,一方面他并没有模块化,代码逻辑容易混乱,也造成了内部的变量命名比较混乱。另一方面:因为登录的代码逻辑影响着其他部分,它自身又不能很好的维护自身的所有逻辑。
 
 
而我们又想要去解决这个问题,那么发布,订阅,消息系统来了。
 
 

 

4. 改进的方法:降低耦合度,维护自身逻辑

 
先看写法:
<script type="text/javascript">
	//我是head的代码逻辑
	(function(){
		core.listen('login', function(info) {
			$("#head name").html(info.name);
		});
	})()

	//我是content的代码逻辑
	(function() {
		core.listen('login', function(info) {
			$("#content").html(info.content);
		})
	})()

	//我是登录的逻辑
	(function() {
		$.ajax({
			url:'http://blog.csdn.net/lihchweb',
			data:{},
			success: function(info) {
				core.send('login', info)	
			}
		})
	})();
</script>
 
这样处理问题的方法就回到的各自的逻辑当中。当我登录完成的时候,各个部分单独处理自己的问题,模块更独立,代码易维护且不易出错。
 
这就是消息机制。
 
这个core是自定义的,你可以定义lihch当然其他什么都行。
 
接下来就回到了我们最初的问题,要将这些数据存储起来。如下:
<script type="text/javascript">
	var callback = {
		login: [],
		req:[],
		lihch:[]
	}
	var core = {
		listen: function(id, handler) {
			callback[id].push(handler)
		},
		send: function(id, data) {
			var cbs = callback[id];
			for (var i = 0; i < cbs.length; i++) {
				cbs[i](data);
			}
		}
</script>

 
在listen里: 我们将得到的方法(lihch方法,req方法,login方法等)添加(push)到数组里。
 
在send里: 我们遍历listen中存储的方法(比如(lihch方法))。并逐个触发:lihch(data);
 

5.更好的方法

 
上面4方法中有两个全局变量:callback core 我们尝试将其合并起来:
 
var core = {
		callback: {
			login: [],
			req:[],
			lihch:[]
		},
		listen: function(id, handler) {
			this.callback[id].push(handler)
		},
		send: function(id, data) {
			var cbs = callback[id];
			for (var i = 0; i < cbs.length; i++) {
				cbs	[i](data);
			}
		}
	}

 
这样对面只暴露一个core,通过core.listen, core.send去执行。
 
这样看似很美好,但是这个core.callback 谁都可以访问到,在多人配合的情况下,难免出现类似于这样的问题: core.callback = null;
 
好吧 ,那所有注册的方法都失效了。为了保护它,我们继续修改:
 
var core = (function() {
		var callback = {
			login: [],
			req:[],
			lihch:[]
		};
		return {
			listen: function(id, handler) {
			   callback[id].push(handler)
			},
			send: function(id, data) {
				var cbs = callback[id];
				for (var i = 0; i < cbs.length; i++) {
					cbs	[i](data);
				}
			}
		}
	})();

 

我们把他放进一个闭包里面,只暴露listen和send这个两个接口。callback是被包在core内部的变量,外部是访问不到的。

 
但是这个时候还有一个问题: callback里我们预设了lihch,login,req方法,但是我们又不知道页面中到底会传过来什么用的消息,那如果要监听的是 lihouchun 呢, 有要修改上面的代码,在callback里加上   lihouchun: []; 
 
显然这样也不是我们想要的,能不能让他智能点呢?
 
var core = (function() {

		var callback = {};
		
		return {
			listen: function(id, handler) {
				callback[id] = callback[id] || [];
				callback[id].push(handler)
			},
			send: function(id, data) {
				var cbs = callback[id];
				if (!cbs) return;
				for (var i = 0; i < cbs.length; i++) {
					cbs	[i](data);
				}
			}
		}
	})();

 
这样,烦恼没有了,listen的时候他会自动判断添加,并且send的时候也做了处理。
 
这就是消息机制,有了它,对代码的耦合性就大大降低,模块更加独立,容错性更强。
 
   
此文后续: 观察者模式和发布订阅模式。 链接:   https://blog.csdn.net/lihchweb/article/details/104001403
 
 
 
 

猜你喜欢

转载自blog.csdn.net/lihchweb/article/details/59552636