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 相关文章推荐
Dreamweaver jQuery智能提示插件,支持版本提示,支持1.6api
Jul 31 Javascript
jQuery 全选/反选以及单击行改变背景色实例
Jul 02 Javascript
javascript中apply和call方法的作用及区别说明
Feb 14 Javascript
Node.js DES加密的简单实现
Jul 07 Javascript
jquery.serialize() 函数语法及简单实例
Jul 08 Javascript
一次$.getJSON不执行的简单记录
Jul 19 Javascript
JS中LocalStorage与SessionStorage五种循序渐进的使用方法
Jul 12 Javascript
mui开发中获取单选按钮、复选框的值(实例讲解)
Jul 24 Javascript
bootstrap table方法之expandRow-collapseRow展开或关闭当前行数据
Aug 09 Javascript
Node.js中,在cmd界面,进入退出Node.js运行环境的方法
May 12 Javascript
js JSON.stringify()基础详解
Jun 19 Javascript
Vue通过阿里云oss的url连接直接下载文件并修改文件名的方法
Dec 25 Vue.js
常用的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带抄送和密件抄送的邮件发送方法
2015/03/20 PHP
JSON两种结构之对象和数组的理解
2016/07/19 PHP
PHP中检索字符串的方法分析【strstr与substr_count方法】
2017/02/17 PHP
PHP设计模式之模板方法模式定义与用法详解
2018/04/02 PHP
YII框架实现自定义第三方扩展操作示例
2019/04/26 PHP
Laravel框架查询构造器简单示例
2019/05/08 PHP
textContent在Firefox下与innerText等效的属性
2007/05/12 Javascript
js事件冒泡实例分享(已测试)
2013/04/23 Javascript
js实现同一页面可多次调用的图片幻灯切换效果
2015/02/28 Javascript
jQuery Uploadify 上传插件出现Http Error 302 错误的解决办法
2015/12/12 Javascript
jQuery实现下拉框功能实例代码
2016/05/06 Javascript
原生js实现键盘控制div移动且解决停顿问题
2016/12/05 Javascript
ES6新特性七:数组的扩充详解
2017/04/21 Javascript
NodeJS链接MySql数据库的操作方法
2017/06/27 NodeJs
Vue中的vue-resource示例详解
2018/11/02 Javascript
从源码里了解vue中的nextTick的使用
2018/11/22 Javascript
微信小程序云开发如何使用npm安装依赖
2019/05/18 Javascript
Vue+element 解决浏览器自动填充记住的账号密码问题
2019/06/11 Javascript
vue实现输入一位数字转汉字功能
2019/12/13 Javascript
小程序实现长按保存图片的方法
2019/12/31 Javascript
手把手带你搭建一个node cli的方法示例
2020/08/07 Javascript
解决vue单页面应用进入页面加载所有 js 的问题
2020/08/12 Javascript
详解Swift中属性的声明与作用
2016/06/30 Python
Python 内置函数memoryview(obj)的具体用法
2017/11/23 Python
numpy.random模块用法总结
2019/05/27 Python
python中pytest收集用例规则与运行指定用例详解
2019/06/27 Python
Django组件content-type使用方法详解
2019/07/19 Python
keras实现多种分类网络的方式
2020/06/11 Python
父亲追悼会答谢词
2014/01/17 职场文书
优秀小学生家长评语
2014/01/30 职场文书
雏鹰争章活动总结
2014/05/09 职场文书
单位接收函范文
2015/01/30 职场文书
元旦主持词开场白
2015/05/29 职场文书
HTML基础-标签分类(闭合标签,空标签,块级元素,行内元素,行级块元素,可替换元素)
2021/03/31 HTML / CSS
关于python类SortedList详解
2021/09/04 Python
四十九个javascript小知识实用技巧
2021/11/20 Javascript