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 相关文章推荐
Javascript面向对象扩展库代码分享
Mar 27 Javascript
jquery处理json对象
Nov 03 Javascript
JavaScript内存管理介绍
Mar 13 Javascript
Javascript中匿名函数的调用与写法实例详解(多种)
Jan 26 Javascript
如何通过js实现图片预览功能【附实例代码】
Mar 30 Javascript
JavaScript数据绑定实现一个简单的 MVVM 库
Apr 08 Javascript
真正好用的js验证上传文件大小的简单方法
Oct 27 Javascript
vue2.0父子组件及非父子组件之间的通信方法
Jan 21 Javascript
详解jQuery同步Ajax带来的UI线程阻塞问题及解决办法
Aug 09 jQuery
JavaScript实现各种排序的代码详解
Aug 28 Javascript
javascript基于定时器实现进度条功能实例
Oct 13 Javascript
在Vue项目中引入腾讯验证码服务的教程
Apr 03 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
解析PHP无限级分类方法及代码
2013/06/21 PHP
PHP设计模式之观察者模式(Observer)详细介绍和代码实例
2014/04/08 PHP
PHP实现文件上传和多文件上传
2015/12/24 PHP
php 数组字符串搜索array_search技巧
2016/07/05 PHP
laravel实现上传图片并在页面显示的例子
2019/10/14 PHP
phpStorm2020 注册码
2020/09/17 PHP
JavaScript高级程序设计 阅读笔记(四) ECMAScript中的类型转换
2012/02/27 Javascript
Extjs4.0设置Ext.data.Store传参的请求方式(默认为GET)
2013/04/02 Javascript
基于javascript实现全屏漂浮广告
2016/03/31 Javascript
javaScript中的原型解析【推荐】
2016/05/05 Javascript
jQuery轻松实现表格的隔行变色和点击行变色的实例代码
2016/05/09 Javascript
Vue 2.0学习笔记之使用$refs访问Vue中的DOM
2017/12/19 Javascript
Vue路由切换时的左滑和右滑效果示例
2018/05/29 Javascript
微信小程序wx:for循环的实例详解
2018/10/07 Javascript
对Layer UI 模块化的用法详解
2019/09/26 Javascript
JS控制只能输入数字并且最多允许小数点两位
2019/11/24 Javascript
Python新手实现2048小游戏
2015/03/31 Python
深入理解Django的自定义过滤器
2017/10/17 Python
Python+树莓派+YOLO打造一款人工智能照相机
2018/01/02 Python
python使用tcp实现局域网内文件传输
2020/03/20 Python
python中的单引号双引号区别知识点总结
2019/06/23 Python
Pycharm 2020.1 版配置优化的详细教程
2020/08/07 Python
Python并发爬虫常用实现方法解析
2020/11/19 Python
ghd澳大利亚官方网站:英国最受欢迎的美发工具品牌
2018/05/21 全球购物
Bailey帽子官方商店:Bailey Hats
2018/09/25 全球购物
中国旅游网站:途牛旅游网
2019/09/29 全球购物
爱尔兰橄榄球店:Irish Rugby Store
2019/12/05 全球购物
美国在线肉类和海鲜配送:Crowd Cow
2020/10/02 全球购物
Linux中如何设置Java环境变量(Ubuntu)
2016/07/24 面试题
WEB控件及HTML服务端控件能否调用客户端方法?如果能,请解释如何调用?
2015/08/25 面试题
小学新学期教师寄语
2014/01/18 职场文书
党校个人自我鉴定范文
2014/03/28 职场文书
品牌转让协议书
2014/08/20 职场文书
学校运动会广播稿100条
2014/09/14 职场文书
2016高考感言
2015/08/01 职场文书
执行力心得体会范文
2016/01/11 职场文书