JavaScript观察者模式的运用
观察者模式,是设计模式中的一种,具体含义和说明,这里就不写了,可以执行百度,这里主要讲解如何使用?如何改善现有的代码逻辑?如何解耦?等问题
一、最简单的例子
$("#test").on("click",function(e){
alert("hi");
});
这是jQuery
中的监听元素的点击事件,然后做出响应;其实这就是观察者模式的运用;监听某个事件,让其它模块来响应你,可能光这么说,感受不出它的好处,看下面的实例。
二、常规的模块间调用
用一个比较直接的例子说明,每个游戏中,都有生命值这个概念,当生命值为0时就结束游戏,假设有三个模块:Life-生命值管理模块,Animation-动画模块,Dead-死亡模块
//生命值管理模块
var Life = function(){
//最大生命值
var _max = 100;
//当前生命值
var _life = 100;
//生命值变化接口
function lifeChange(diff){
//增加或者扣血
_life += diff;
//调用其它模块生命值变化接口
Animation.lifeChange({life:_life,diff:diff});
Dead.lifeChange({life:_life,diff:diff});
}
return {
lifeChange : lifeChange
}
}();
//动画模块,显示生命值变化动画
var Animation = function(){
return {
lifeChange : function(param){
$("#life").animation({width:param.life + "px"});
}
};
}
//死亡模块,当生命值为空时结束游戏
var Dead = function(){
return {
lifeChange : function(param){
if(param.life <= 0)return alert("game over");
}
}
}();
上面是简单的三个模块实现逻辑,大致思路为:
- 当生命值发生变化的时候,即有怪物砍了你一刀,调用了
Life.lifeChange(-20)
函数。 - 这个时候,生命值需要发生改变,
_lift
减掉20
- 然后需要让生命变化的过程有动画,调用了动画模块的
Animation.lifeChange
函数 - 之后要判断是否死亡了,调用了死亡模块的
Dead.lifeChange
函数
存在的问题
- 模块之间高度耦合,
Life
和Animation
、Dead
之间存在互相依赖的关系 - 如果需要增加一个新模块,比如
满血模块
,会增加攻击力等,那你又需要在Life
里增加一次函数调用,耦合的模块又增加多一个 - 不灵活,无法在当前模块,比如:
Dead
,得知lifeChange
的调用在哪?以及时机?后期维护变得头疼
思考?要是能像jQuery的点击事件监听那样就好了~~
三、自定义事件监控和调用
自己实现类似jQuery的监听和调用的逻辑,使得模块的耦合降低
//简单的事件监听和执行
var Proxy = function(){
//保存所有代理
var _Proxy = {};
return {
//监听代理
onProxy : function(namespace,action,func){
//创建命名空间,避免事件名冲突
if(!Proxy[namespace])Proxy[namespace] = {};
if(!Proxy[namespace][action]) Proxy[namespace][action] = [];
//添加代理到队列中
Proxy[namespace][action].push(func);
},
//执行代理
execProxy : function(namespace,action,param){
if(!Proxy[namespace])return false;
if(!Proxy[namespace][action])return false;
//遍历代理队列,执行函数
for(var i=0;i<Proxy[namespace][action].length;i++){
Proxy[namespace][action][i](param);
}
}
};
}();
实现思路
- 需要在原本调用
lifeChange
的地方,执行代理,即示例中的Life.lifeChange
函数中 - 需要在原本提供接口给外部调用的模块,增加监听,即示例中的
Dead.lifeChange
和Animation.lifeChange
- 修改如下
//生命值管理模块
var Life = function(){
//最大生命值
var _max = 100;
//当前生命值
var _life = 100;
//生命值变化接口
function lifeChange(diff){
//增加或者扣血
_life += diff;
//执行生命值变量变化的事件代理
Proxy.execProxy("Life","lifeChange",{life:_life,diff:diff});
}
return {
lifeChange : lifeChange
}
}();
//动画模块,显示生命值变化动画
var Animation = function(){
function init(){
//监听生命值变化
Proxy.onProxy("Life","lifeChange",function(param){
$("#life").animation({width:param.life + "px"});
});
}
init();
}
//死亡模块,当生命值为空时结束游戏
var Dead = function(){
function init(){
//监听生命值变化
Proxy.onProxy("Life","lifeChange",function(param){
if(param.life <= 0)return alert("game over");
});
}
init();
}();
实现逻辑
Life
模块中,不再需要知道具体需要调用哪个模块的哪个函数了,只需要统一执行一次代理就可以了Animation
和Dead
模块,不再需要提供接口给外部了,只需要监听lifeChange
事件,就可以执行对应的逻辑- 强制解耦三个模块之间的联系
- 即使增加多几个模块,也不需要修改
Life
模块,各自模块监听需要的事件即可
小结
设计模式,在很多时候能够帮助我们更好的管理和设计代码、模块等,善加利用,能够事半功倍
手机阅读请扫描下方二维码:
上一篇:横屏页面注意事项
下一篇:记my官网改版遇到的自己挖的坑
[...]来源:http://feg.netease.com/archives/242.html 阅读(1)[...]
1
1
1
1
1
1
1
1
1
1
1
12345678
12345678
12345678
dzvqtzhurtkzreeqhasz
12345678
12345678
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1