观察者模式( 又叫发布者-订阅者模式 )应该是最常用的模式之一.
在很多语言里都得到大量应用. 包括我们平时接触的dom事件. 也是js和dom之间实现的一种观察者模式.
div.onclick = function click (){
alert ('click');
};
只要订阅了div的click事件. 当点击div的时候, function click就会被触发.
那么到底什么是观察者模式呢. 先看看生活中的观察者模式。
好莱坞有句名言. “不要给我打电话, 我会给你打电话”.* 这句话就解释了一个观察者模式的来龙去脉。 其中“我”是发布者, “你”是订阅者。
再举个例子,我来公司面试的时候,完事之后每个面试官都会对我说:“请留下你的联系方式, 有消息我们会通知你”。 在这里“我”是订阅者, 面试官是发布者。所以我不用每天或者每小时都去询问面试结果, 通讯的主动权掌握在了面试官手上。而我只需要提供一个联系方式。
观察者模式可以很好的实现2个模块之间的解耦。 假如我正在一个团队里开发一个html5游戏. 当游戏开始的时候,需要加载一些图片素材。加载好这些图片之后开始才执行游戏逻辑. 假设这是一个需要多人合作的项目. 我完成了Gamer和Map模块, 而我的同事A写了一个图片加载器loadImage.
loadImage的代码如下
loadImage(imgAry, function(){
Map.init();
Gamer.init();
});
当图片加载好之后, 再渲染地图, 执行游戏逻辑. 嗯, 这个程序运行良好. 突然有一天, 我想起应该给游戏加上声音功能. 我应该让图片加载器添上一行代码.
loadImage(imgAry, function(){
Map.init();
Gamer.init();
Sount.init();
});
可是写这个模块的同事A去了外地旅游. 于是我打电话给他, 喂. 你的loadImage函数在哪, 我能不能改一下, 改了之后有没有副作用. 如你所想, 各种不淡定的事发生了. 如果当初我们能这样写呢:
loadImage.listen('ready', function(){
Map.init();
});
loadImage.listen('ready', function(){
Gamer.init();
});
loadImage.listen('ready', function(){
Sount.init();
});
loadImage完成之后, 它根本不关心将来会发生什么, 因为它的工作已经完成了. 接下来它只要发布一个信号.
loadImage.trigger('ready');
那么监听了loadImage的’ready’事件的对象都会收到通知. 就像上个面试的例子. 面试官根本不关心面试者们收到面试结果后会去哪吃饭. 他只负责把面试者的简历搜集到一起. 当面试结果出来时照着简历上的电话挨个通知.
说了这么多概念, 来一个具体的实现. 实现过程其实很简单. 面试者把简历扔到一个盒子里, 然后面试官在合适的时机拿着盒子里的简历挨个打电话通知结果.
var Events = function () {
obj = {};
__this = this;
listen = function (key, eventfn) { //把简历扔盒子, key就是联系方式.
var stack, _ref; //stack是盒子
stack = (_ref = obj[key]) != null ? _ref : obj[key] = [];
return stack.push(eventfn);
};
one = function (key, eventfn) {
remove(key);
return listen(key, eventfn);
};
remove = function (key) {
var _ref;
return (_ref = obj[key]) != null ? _ref.length = 0 : void 0;
};
trigger = function () { //面试官打电话通知面试者
var fn, stack, _i, _len, _ref, key;
key = Array.prototype.shift.call(arguments);
stack = (_ref = obj[key]) != null ? _ref : obj[key] = [];
for (_i = 0, _len = stack.length; _i < _len; _i++) {
fn = stack[_i];
if (fn.apply(__this, arguments) === false) {
return false;
}
}
return {
listen : listen,
one : one,
remove : remove,
trigger: trigger
}
};
}
最后用观察者模式来做一个成人电视台的小应用.
//订阅者
var adultTv = Event();
adultTv.listen('play', function(data){
alert("今天是谁的电影" + data.name);
});
//发布者
adultTv .trigger('play', { 'name': '麻生希' })
“你不知道的 javascript 设计模式系列” ~( ̄▽ ̄)~
- 单例模式
- 简单工厂模式
- 观察者模式
- 适配器模式
- 代理模式
- 桥接模式
- 外观模式
- 访问者模式
- 策略模式
- 模版方法模式
- 中介者模式
- 迭代器模式
- 组合模式
- 备忘录模式
- 职责链模式
- 享元模式
- 状态模式
转载自 AlloyTeam
http://www.alloyteam.com/2012/10/commonly-javascript-design-pattern-observer-mode/