JavaScript观察者模式(经典)


Posted in Javascript onDecember 09, 2015

Observer模式也叫观察者模式,是由GoF提出的23种软件设计模式的一种。Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。

Observer模式的概念

Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。
Observer模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步。

Observer模式的角色:

Subject(被观察者)
被观察的对象。当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。Subject需要维持(添加,删除,通知)一个观察者对象的队列列表。
ConcreteSubject
被观察者的具体实现。包含一些基本的属性状态及其他操作。
Observer(观察者)
接口或抽象类。当Subject的状态发生变化时,Observer对象将通过一个callback函数得到通知。
ConcreteObserver
观察者的具体实现。得到通知后将完成一些具体的业务逻辑处理。

观察者模式( 又叫发布者-订阅者模式 )应该是最常用的模式之一. 在很多语言里都得到大量应用. 包括我们平时接触的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'事件的对象都会收到通知. 就像上个面试的例子. 面试官根本不关心面试者们收到面试结果后会去哪吃饭. 他只负责把面试者的简历搜集到一起. 当面试结果出来时照着简历上的电话挨个通知.

说了这么多概念, 来一个具体的实现. 实现过程其实很简单. 面试者把简历扔到一个盒子里, 然后面试官在合适的时机拿着盒子里的简历挨个打电话通知结果.

Events = function() {
var listen, log, obj, one, remove, trigger, __this;
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 相关文章推荐
baidu博客的编辑友情链接的新的层窗口!经典~支持【FF】
Feb 09 Javascript
基于jquery的tab切换 js原理
Apr 01 Javascript
javascript代码编写需要注意的7个小细节小结
Sep 21 Javascript
jquery实现一个简单的表单验证实例
Mar 30 Javascript
Angular.JS通过指令操作DOM的方法
May 10 Javascript
详解vue嵌套路由-query传递参数
May 23 Javascript
深入理解react-router@4.0 使用和源码解析
May 23 Javascript
微信小程序promsie.all和promise顺序执行
Oct 27 Javascript
微信小程序使用for循环动态渲染页面操作示例
Dec 25 Javascript
解决vue做详情页跳转的时候使用created方法 数据不会更新问题
Jul 24 Javascript
react的hooks的用法详解
Oct 12 Javascript
Node.js利用Express实现用户注册登陆功能(推荐)
Oct 26 Javascript
常用的Javascript设计模式小结
Dec 09 #Javascript
JS实现字符串转日期并比较大小实例分析
Dec 09 #Javascript
jQuery实现批量判断表单中文本框非空的方法(2种方法)
Dec 09 #Javascript
详解JavaScript基本类型和引用类型
Dec 09 #Javascript
jQuery中serializeArray()与serialize()的区别实例分析
Dec 09 #Javascript
jQuery实现form表单元素序列化为json对象的方法
Dec 09 #Javascript
jQuery实现页面顶部显示的进度条效果完整实例
Dec 09 #Javascript
You might like
linux环境apache多端口配置虚拟主机的方法深入介绍
2013/06/09 PHP
php使用sql数据库 获取字段问题介绍
2013/08/12 PHP
php模拟ping命令(php exec函数的使用方法)
2013/10/25 PHP
PHP并发多进程处理利器Gearman使用介绍
2016/05/16 PHP
微信支付扫码支付php版
2016/07/22 PHP
php获取小程序码的实现代码(B类接口)
2020/06/13 PHP
javascript中的关于类型转换的性能优化
2010/12/14 Javascript
基于jquery循环map功能的代码
2011/02/26 Javascript
解决3.01版的jquery.form.js中文乱码问题的解决方法
2012/03/08 Javascript
jquery中的过滤操作详细解析
2013/12/02 Javascript
JS继承用法实例分析
2015/02/05 Javascript
Nodejs从有门道无门菜鸟起飞必看教程
2016/07/20 NodeJs
javascript中Number的方法小结
2016/11/21 Javascript
详解node HTTP请求客户端 - Request
2017/05/05 Javascript
JavaScript代码判断输入的字符串是否含有特殊字符和表情代码实例
2017/08/17 Javascript
基于jQuery选择器之表单对象属性筛选选择器的实例
2017/09/19 jQuery
Vue.set()实现数据动态响应的方法
2018/02/07 Javascript
详解vue移动端项目的适配(以mint-ui为例)
2018/08/17 Javascript
详解vue配置后台接口方式
2019/03/29 Javascript
JS实现简单的文字无缝上下滚动功能示例
2019/06/22 Javascript
python实现的一个p2p文件传输实例
2014/06/04 Python
采用Psyco实现python执行速度提高到与编译语言一样的水平
2014/10/11 Python
在Python中使用AOP实现Redis缓存示例
2017/07/11 Python
浅谈Python黑帽子取代netcat
2018/02/10 Python
PYQT5实现控制台显示功能的方法
2019/06/25 Python
python多环境切换及pyenv使用过程详解
2019/09/27 Python
HTML5本地存储之Database Storage应用介绍
2013/01/06 HTML / CSS
html5简单示例_动力节点Java学院整理
2017/07/07 HTML / CSS
Chain Reaction Cycles俄罗斯:世界上最大的在线自行车商店
2019/08/27 全球购物
关于赌博的检讨书
2014/01/08 职场文书
京剧自荐信
2014/01/26 职场文书
自我鉴定 电子商务专业
2014/01/30 职场文书
创建绿色学校先进个人材料
2014/08/20 职场文书
2015年六一儿童节活动方案
2015/05/05 职场文书
PostgreSQL解析URL的方法
2021/08/02 PostgreSQL
Android开发手册TextInputLayout样式使用示例
2022/06/10 Java/Android