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 相关文章推荐
使用js获取QueryString的方法小结
Feb 28 Javascript
鼠标放在图片上显示大图的JS代码
Mar 26 Javascript
jquery中子元素和后代元素的区别示例介绍
Apr 02 Javascript
JavaScript 学习笔记之操作符(续)
Jan 14 Javascript
JavaScript中解析JSON数据的三种方法
Jul 03 Javascript
JS鼠标拖拽实例分析
Nov 23 Javascript
JavaScript脚本库编写的方法
Dec 09 Javascript
Vue.js学习教程之列表渲染详解
May 17 Javascript
Vue动态组件实例解析
Aug 20 Javascript
vue-cli初始化项目中使用less的方法
Aug 09 Javascript
Mint-UI时间组件起始时间问题及时间插件使用
Aug 20 Javascript
vue src动态加载请求获取图片的方法
Oct 17 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系统下php获得系统分区信息的方法
2015/03/30 PHP
JavaScript日历实现代码
2010/09/12 Javascript
JavaScript 一道字符串分解的题目
2011/08/03 Javascript
JS实现table表格数据排序功能(可支持动态数据+分页效果)
2016/05/26 Javascript
jQuery实现的省市县三级联动菜单效果完整实例
2016/08/01 Javascript
响应式表格之固定表头的简单实现
2016/08/26 Javascript
有关文件上传 非ajax提交 得到后台数据问题
2016/10/12 Javascript
Vue 固定头 固定列 点击表头可排序的表格组件
2016/11/25 Javascript
JS变量中有var定义和无var定义的区别以及es6中let命令和const命令
2017/02/19 Javascript
Vue制作Todo List网页
2017/04/26 Javascript
vue-cli开发时,关于ajax跨域的解决方法(推荐)
2018/02/03 Javascript
解决vue项目中type=”file“ change事件只执行一次的问题
2018/05/16 Javascript
javascript深拷贝、浅拷贝和循环引用深入理解
2018/05/27 Javascript
webpack实现一个行内样式px转vw的loader示例
2018/09/13 Javascript
微信小程序解析富文本过程详解
2019/07/13 Javascript
JavaScript实现简单计算器功能
2019/12/19 Javascript
[02:07]DOTA2新英雄展现中国元素,完美“圣典”亮相央视
2016/12/19 DOTA
[41:41]TFT vs Secret Supermajor小组赛C组 BO3 第一场 6.3
2018/06/04 DOTA
Python的地形三维可视化Matplotlib和gdal使用实例
2017/12/09 Python
python3+mysql查询数据并通过邮件群发excel附件
2018/02/24 Python
解决Pandas to_json()中文乱码,转化为json数组的问题
2018/05/10 Python
python网络爬虫 CrawlSpider使用详解
2019/09/27 Python
基于Python把网站域名解析成ip地址
2020/05/25 Python
Python实现简单的猜单词小游戏
2020/10/28 Python
Python实现石头剪刀布游戏
2021/01/20 Python
CSS3中的Media Queries学习笔记
2016/05/23 HTML / CSS
世界上最全面的汽车零部件和配件集合:JC Whitney
2016/09/04 全球购物
含精油的天然有机化妆品:Indemne
2019/08/27 全球购物
一份全面的PHP面试问题考卷
2012/07/15 面试题
一套比较完整的软件测试人员面试题
2012/05/13 面试题
材料工程专业毕业生求职信
2014/03/04 职场文书
实习推荐信
2014/05/10 职场文书
老人再婚离婚协议书范本
2014/10/27 职场文书
高一英语教学反思
2016/03/03 职场文书
温馨祝福晨语:美丽的一天从我的问候开始
2019/11/28 职场文书
TaiShan 200服务器安装Ubuntu 18.04的图文教程
2022/06/28 Servers