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)简单 ...
随机推荐
- int,int32_t,int64_t
一.数据类型特别是int相关的类型在不同位数机器的平台下长度不同.C99标准并不规定具体数据类型的长度大小,只规定级别.作下比较: 16位平台 char 1个字节8位short ...
- xpath语法大全
XPath 节点 XPath 术语 节点 在 XPath 中,有七种类型的节点:元素.属性.文本.命名空间.处理指令.注释以及文档(根)节点.XML 文档是被作为节点树来对待的.树的根被称为文档节点或 ...
- SQL Server 事务隔离级别
一.事务隔离级别控制着事务的如下表现: 读取数据时是否占用锁以及所请求的锁类型. 占用读取锁的时间. 引用其他事务修改的行的读操作是否: 在该行上的排他锁被释放之前阻塞其他事务. 检索在启动语句或事务 ...
- Flask中的CBV
Flask中的CBV 第一种 class Index(views.MethodView): methods = ['GET', 'POST'] decorators = [] def get(self ...
- AndroidNDK开发中使用CMake编译JNI
虽然一直在做NDK的开发工作,但是由于项目比较久远,都是使用Makefile进行底层编译,对于目前AndroidStudio官方提供的CMake编译方式并不是很了解,现在学习下这种已经不算新潮的新方式 ...
- 【算法】LeetCode算法题-Longest Common Prefix
这是悦乐书的第146次更新,第148篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第5题(顺位题号是14),给定一个随机的字符串数组,查找这些字符串元素的公共前缀字符串, ...
- Loj #2731 「JOISC 2016 Day 1」棋盘游戏
Loj 2731 「JOISC 2016 Day 1」棋盘游戏 JOI 君有一个棋盘,棋盘上有 \(N\) 行 \(3\) 列 的格子.JOI 君有若干棋子,并想用它们来玩一个游戏.初始状态棋盘上至少 ...
- 【FJWC 2019】min
[FJWC 2019]min 题目描述 给你一张 \(n\) 个点 \(m\) 条边的无向图,走过每条边都需要花费 \(1\) 秒. 给你一个整数 \(k\) ,请你选择至多 \(k\) 个点,令经过 ...
- 设计模式のFactoryPattern(工厂模式)----创建模式
一.产生背景 设计一个连接服务器的框架,需要三个协议,"POP3"."IMAP"."HTTP",可以把这三个作为产品类,共同实现一个接口. ...
- SQL BETWEEN 操作符
BETWEEN 操作符在 WHERE 子句中使用,作用是选取介于两个值之间的数据范围. BETWEEN 操作符 操作符 BETWEEN ... AND 会选取介于两个值之间的数据范围.这些值可以是数值 ...