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)简单 ...
随机推荐
- [译]在Linux上的提高MySQL/MariaDB安全性的12条建议
MySQL 是世界上最流行的开源数据库系统,而MariaDB(MySQL的一个分支)是世界上发展最快的开源数据库系统.安装MySQL服务器之后,它的默认配置是不安全的,保护它是一般数据库管理中的基本任 ...
- 使用VSTS的Git进行版本控制(五)——从Team Services Portal管理分支
使用VSTS的Git进行版本控制(五)--从Team Services Portal管理分支 任务1:创建新分支 1.登录Visual Studio Team Services账号 2.打开Code ...
- python中封装、继承、多态
又看到这个玩意,顺手写下来 面向对象三大特征: 封装:本质是将事物相关的属性和方法封装在一个类里面,我们调用类创建实例的时候,不用关心类内部的代码细节 继承:子类需要复用父类里面的属性或者方法,当然子 ...
- php5.4新功能Traits
php5.4新功能Traits介绍 1. traits Traits是在5.4中新增的一个用于实现代码重用的方法. php是一种单一继承的语言,我们无法像java一样在一个class中extends多 ...
- C# -- 随机数产生的字母金字塔
C# -- 随机数产生的字母金字塔 1. 代码实现: static void Main(string[] args) { showNpoint(); Console.ReadKey(); } priv ...
- (转载)关于usr/bin/ld: cannot find -lxxx问题总结
usr/bin/ld: cannot find -lxxx问题总结 linux下编译应用程序常常会出现如下错误: /usr/bin/ld: cannot find -lxxx 意思是 ...
- Linux 小知识翻译 - 「代理服务器」
这回聊聊「代理服务器」. 在公司里,不通过代理服务器无法连接互联网的,由于代理服务器的原因,有些服务的使用是受到限制的. 有人可能会觉得为什么会存在这种东西?(这里指代理服务器) Proxy本来的意思 ...
- #000 Python 入门第一题通过扩展,学到了更多的知识
#1写在前面的话 我觉得这样学习或许能够在学习的过程中事半功倍 第一道简单的python编写代码输出10行带标号的“Hello,world.”,具体效果参阅输入输出示例 1:Hello,world. ...
- contenteditable元素的placeholder输入提示语设置
在某些情况下,textarea是不够用的,我们还需要显示一些图标或者高亮元素,这就需要用富文本编辑器,而富文本编辑器本质上是HTML元素设置了contenteditable. 然后可能需要像input ...
- Java实现鼠标随机移动
---恢复内容开始--- 以前在公司工作的时候,电脑限制重重,不允许改锁屏时间,又不允许下载和安装软件. 需要在家办公support的时候,又没有什么事,但还是必须在线,所以就写了个小程序让鼠标自己随 ...