Javascript设计模式之我见:观察者模式
大家好!本文介绍观察者模式及其在Javascript中的应用。
模式介绍
定义
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
类图及说明
Subject:主题\发布者
能够动态地增加、取消观察者。它负责管理观察者并通知观察者。
Observer:观察者\订阅者
观察者收到消息后,即进行update操作,对接收到的信息进行处理。
ConcreteSubject:具体的主题\发布者
定义主题自己的业务逻辑,同时定义对哪些事件进行通知。
ConcreteObserver:具体的观察者\订阅者
每个观察者在接受到消息后的处理反应时不同的,各个观察者有自己的处理逻辑。
应用场景
- 当一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变。
当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。
对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。
优点
- 支持简单的广播通信,自动通知所有已经订阅过的对象。
- 页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。
- 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。
缺点
1、 松偶合导致代码关系不明显,有时可能难以理解。
2、 如果一个Subject被大量Observer订阅的话,在广播通知的时候可能会有效率问题。
观察者模式在Javascript中的应用
类图及说明
这里有两个变化:
- ConcreteSubject与Subject的继承关系改为委托关系。
- 删除了Observer基类,直接将观察者的update方法订阅到Subject的events数组中。
应用场景
- 一个对象变化时触发多个对象变化
- 一个对象调用其他对象的方法,而又不想与之耦合
示例
现在是找工作的季节,大家都在忙着找工作。大神可以单枪匹马秒杀各种offer,高富帅也有各种关系帮忙找工作。
让我们来看下高富帅是如何找工作的。
类图
代码
GaoFuShuai
function GaoFuShuai() {
this._wang = new Wang();
} GaoFuShuai.prototype.findJob = function () {
console.log("高富帅开始找工作了");
this._wang.help();
};
王哥
function Wang() {
} Wang.prototype.help = function () {
console.log("高富帅找工作啊,王哥来助你");
}
场景
function main() {
var gaofushuai = new GaoFuShuai(); gaofushuai.findJob();
}
运行结果
分析
本设计有以下的缺点:
- 观察者可能不止一个,如果增加李哥、张哥等观察类,那就都要对应修改高富帅类,不符合开闭原则。
- 观察者可能不仅仅要观察高富帅的找工作情况,还要观察高富帅的上学、娱乐等情况,这样会有严重的耦合问题。
使用观察者模式
现在使用观察者模式来改进设计。
类图
代码
Subject
(function () {
if (!Array.prototype.forEach) {
Array.prototype.forEach = function (fn, thisObj) {
var scope = thisObj || window;
for (var i = , j = this.length; i < j; ++i) {
fn.call(scope, this[i], i, this);
}
};
} if (!Array.prototype.filter) {
Array.prototype.filter = function (fn, thisObj) {
var scope = thisObj || window;
var a = [];
for (var i = , j = this.length; i < j; ++i) {
if (!fn.call(scope, this[i], i, this)) {
continue;
}
a.push(this[i]);
}
return a;
};
} var Subject = function () {
this._events = [];
} Subject.prototype = (function () {
return {
//订阅方法
subscribe: function (context, fn) {
if (arguments.length == ) {
this._events.push({ context: arguments[], fn: arguments[] });
}
else {
this._events.push(arguments[]);
}
},
//发布指定方法
publish: function (context, fn, args) {
var args = Array.prototype.slice.call(arguments, ); //获得函数参数
var _context = null;
var _fn = null; this._events.filter(function (el) {
if (el.context) {
_context = el.context;
_fn = el.fn;
}
else {
_context = context;
_fn = el;
} if (_fn === fn) {
return _fn;
}
}).forEach(function (el) { //指定方法可能有多个
el.apply(_context, args); //执行每个指定的方法
});
},
unSubscribe: function (fn) {
var _fn = null;
this._events = this._events.filter(function (el) {
if (el.fn) {
_fn = el.fn;
}
else {
_fn = el;
} if (_fn !== fn) {
return el;
}
});
},
//全部发布
publishAll: function (context, args) {
var args = Array.prototype.slice.call(arguments, ); //获得函数参数
var _context = null;
var _fn = null; this._events.forEach(function (el) {
if (el.context) {
_context = el.context;
_fn = el.fn;
}
else {
_context = context;
_fn = el;
} _fn.apply(_context, args); //执行每个指定的方法
});
},
dispose: function () {
this._events = [];
}
}
})(); window.Subject = Subject;
})();
GaoFuShuai
function GaoFuShuai() {
} GaoFuShuai.prototype.findJob = function () {
console.log("高富帅开始找工作了");
window.subject.publishAll(null, "帮忙找工作");
};
GaoFuShuai.prototype.haveFun = function () {
console.log("高富帅开始娱乐了");
window.subject.publishAll(null, "帮忙找乐子");
};
王哥
function Wang() {
} Wang.prototype.help = function (actionStr) {
console.log("王哥" + actionStr);
};
李哥
function Li() {
} Li.prototype.help = function (actionStr) {
console.log("李哥" + actionStr);
};
场景
function main() {
var wang = new Wang(),
li = new Li(),
gaofushuai = new GaoFuShuai(); window.subject = new Subject();
window.subject.subscribe(wang.help);
window.subject.subscribe(li.help); gaofushuai.findJob();
gaofushuai.haveFun();
}
运行结果
分析
这样就符合开闭原则了,被观察者与观察者也不再直接耦合了。如果想继续增加观察者,则只需对应修改main即可,被观察者GaoFuShuai类不用修改。
参考资料
深入理解JavaScript系列(32):设计模式之观察者模式《设计模式之禅》
Javascript设计模式之我见:观察者模式的更多相关文章
- Javascript设计模式之我见:状态模式
大家好!本文介绍状态模式及其在Javascript中的应用. 模式介绍 定义 当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式主要解决的是控制一个对象状态的条件表达式 ...
- Javascript设计模式之我见:迭代器模式
大家好!本文介绍迭代器模式及其在Javascript中的应用. 模式介绍 定义 提供一种方法顺序一个聚合对象中各个元素,而又不暴露该对象内部表示. 类图及说明 Iterator抽象迭代器 抽象迭代器负 ...
- 【读书笔记】读《JavaScript设计模式》之观察者模式
一.定义 在事件驱动的环境中,比如浏览器这种持续寻求用户关注的环境中,观察者模式(又名发布者-订阅者(publisher-subscripber)模式)是一种管理人与其任务之间的关系(确切地讲,是对象 ...
- [转] 浅析JavaScript设计模式——发布-订阅/观察者模式
前一段时间一直在写CSS3的文章 一直都没写设计模式 今天来写写大名鼎鼎观察者模式 先画张图 观察者模式的理解 我觉得还是发布-订阅模式的叫法更容易我们理解 (不过也有的书上认为它们是两种模式……) ...
- JavaScript设计模式与开发实践 - 观察者模式
概述 观察者模式又叫发布 - 订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个目标对象(为了方便理解,以下将观察者对象叫做订阅者,将目标对象叫做 ...
- JavaScript设计模式之观察者模式(学习笔记)
设计模式(Design Pattern)对于软件开发来说其重要性不言而喻,代码可复用.可维护.可扩展一直都是软件工程中的追求!对于我一个学javascript的人来说,理解设计模式似乎有些困难,对仅切 ...
- 再起航,我的学习笔记之JavaScript设计模式18(观察者模式)
观察者模式 观察者模式(Observer): 又被称为发布-订阅者模式或消息机制,定义了一种依赖关系,解决了主体对象与观察者之间功能的耦合. 创建一个观察者对象 首先我们创建一个闭包对象,让其在页面加 ...
- [转] JavaScript设计模式之发布-订阅模式(观察者模式)-Part1
<JavaScript设计模式与开发实践>读书笔记. 发布-订阅模式又叫观察者模式,它定义了对象之间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖它的对象都将得到通知. 例如 ...
- 《JavaScript设计模式 张》整理
最近在研读另外一本关于设计模式的书<JavaScript设计模式>,这本书中描述了更多的设计模式. 一.创建型设计模式 包括简单工厂.工厂方法.抽象工厂.建造者.原型和单例模式. 1)简单 ...
随机推荐
- [iOS]创建界面方法的讨论
以前在入门的时候,找的入门书籍上编写的 demo 都是基于 Storyboards 拖界面的.后来接触公司项目,发现界面都是用纯代码去写复杂的 autoLayout 的.再然后,领导给我发了个 Mas ...
- Python 套接字socketserver网络编程
为什么使用socketserver 虽然Python内置的socket和threading模块能实现简单的多线程服务器,在非正式环境,随便用用还是可以的,但是如果要在生产环境中使用,那是万万不够的. ...
- Oracle EBS when-validate-record 个性化无效果
在对FORM进行个性化时,针对对应块添加 when-validate-record ,结果做实验的时候无效果. 原因: FORM 中对应的 BLOCK 没有 when-validate-record ...
- 自动化测试基础篇--Selenium中JS处理浏览器弹窗
摘自https://www.cnblogs.com/sanzangTst/p/7692454.html 浏览器弹窗: 现在大多数网站都会使用自定义弹窗,使用Selenium自带的方法暂时处理不了,这时 ...
- 【Ubuntu16.04.4】常用配置
1.为root用户设置密码 sudo passwd root 2.设置用户登陆界面 sudo gedit /usr/share/lightdm/lightdm.conf.d/50-unity-gre ...
- SQL Server 创建用户报错:消息 15023,级别 16,状态 1,第 1 行 用户、组或角色 'XXX' 在当前数据库中已存在。
问题描述: 原因: 当数据库恢复到其他服务器时,原数据库中包含一组用户和权限,但可能没有相应的登录或者登录所关联的用户可能不是相同的用户. 这种情况可能会出现上面的问题.该问题是无法通过新建登录或者是 ...
- 下载Eclipse、下载Java各个版本,来这里就对了
Eclipse官网:http://www.eclipse.org/ 不信你去看看 Java官网:https://www.java.com/ 不信你去看看 可惜是,每次进入官网提示都是下面这样的:来,我 ...
- Win10家庭版-添加[组策略]
win10家庭版有很多功能都不能用,这一次就碰到了一个找不到‘组策略’的问题,在网上搜索到了一个方法,记录一下: 新建一个txt,将下面内容复制到文本中: =====分隔符====== @echo o ...
- ASP.NET -- 一般处理程序ashx
ASP.NET -- 一般处理程序ashx 如果在一个html页面向服务器端请求数据,可用ashx作为后台页面处理数据.ashx适合用作数据后台处理,相当于WebForm中的aspx.cs文件或 ...
- jQuery -- 光阴似箭(四):jQuery 遍历
jQuery -- 知识点回顾篇(四):jQuery 遍历 通过 jQuery 遍历,您能够从被选(当前的)元素开始,轻松地在家族树中向上移动(祖先),向下移动(子孙),水平移动(同胞).这种移动被称 ...