介绍

观察者模式又叫发布订阅模式(Publish/Subscribe),一个目标对象管理所有相依于它的观察者对象。该模式中存在两个角色:观察者和被观察者。目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。

该模式通常有两种实现策略:"推"(push) 和 "拉"(pull)

例:对于报社可能雇佣投送人员四处送报给订阅者,这就是主动推送。而对于规模小的报社没有足够的资源去雇佣投送员,这时候可以采取 "拉" 的方式。就是在订阅者附近提供自己的数据,供订阅者 "拉" 自己所需的数据。

实现

push

var Observable = {
observers: []
, lastId: -1
, addObserver: function(observer) {
this.observers.push({
callback: observer
, id: ++this.lastId
}) return this.lastId
}
, removeObserver: function(id) {
for (var i = this.observers.length - 1; i >= 0; i--) {
this.observers[i]
if (this.observers[i].id == id) {
this.observers.splice(i, 1)
return true
}
} return false
}
, notifyObservers: function(message) {
for (var i = this.observers.length - 1; i >= 0; i--) {
this.observers[i].callback(message)
};
}
} var id_1 = Observable.addObserver(function(message){
console.log("First observer message:" + message)
}) var observer = function(message){
console.log("Second observer message:" + message)
} var id_2 = Observable.addObserver(observer) Observable.notifyObservers('test 1')
Observable.removeObserver(id_2)
Observable.notifyObservers('test 2')

pull

var Observable = {}

;(function(O){
var observers = []
, privateVar O.addObserver = function(observer) {
observers.push(observer)
} O.removeObserver = function(observer) {
var index = observers.indexOf(observer) if (~index) {
observers.splice(index, 1)
}
} O.notifyObservers = function() {
for (var i = observers.length - 1; i >= 0; i--) {
observers[i].update()
};
} O.updatePrivate = function(newValue) {
privateVar = newValue
this.notifyObservers()
} O.getPrivate = function() {
return privateVar
}
}(Observable)) Observable.addObserver({
update: function(){
this.process()
}
, process: function(){
var value = Observable.getPrivate()
console.log("Private value is: " + value)
}
}) Observable.updatePrivate('test 1')
// Private value is: test 1 Observable.updatePrivate('test 2')
// Private value is: test 2

被观察对象将通知所有的观察者,并且每个观察者将从被观察对象中提取所需的信息。

让多个对象都具有观察者发布订阅的功能

var observer = {
addSubscriber:function (callback) {
this.subscribers[this.subscribers.length] = callback;
},
removeSubscriber:function (callback) {
for (var i = 0; i < this.subscribers.length; i++) {
if (this.subscribers[i] === callback) {
delete(this.subscribers[i]);
}
}
},
publish:function (what) {
for (var i = 0; i < this.subscribers.length; i++) {
if (typeof this.subscribers[i] === 'function') {
this.subscribers[i](what);
}
}
},
make:function (o) { // turns an object into a publisher
for (var i in this) {
o[i] = this[i];
o.subscribers = [];
}
}
}; var blogger = {
writeBlogPost:function () {
var content = 'Today is ' + new Date();
this.publish(content);
}
};
var la_times = {
newIssue:function () {
var paper = 'Martians have landed on Earth!';
this.publish(paper);
}
}; observer.make(blogger);
observer.make(la_times); var jack = {
read:function (what) {
console.log('I just read that ' + what)
}
};
var jill = {
gossip:function (what) {
console.log('You didn\'t hear it from me, but ' + what)
}
}; blogger.addSubscriber(jack.read);
blogger.addSubscriber(jill.gossip);
blogger.writeBlogPost();
blogger.removeSubscriber(jill.gossip);
blogger.writeBlogPost();
la_times.addSubscriber(jill.gossip);
la_times.newIssue();

避免创建多个被观察者对象,可以增加 "命名空间"

var Observable = {
observers: []
, addObserver: function(topic, observer) {
this.observers[topic] || (this.observers[topic] = []) this.observers[topic].push(observer)
}
, removeObserver: function(topic, observer) {
if (!this.observers[topic])
return; var index = this.observers[topic].indexOf(observer) if (~index) {
this.observers[topic].splice(index, 1)
}
}
, notifyObservers: function(topic, message) {
if (!this.observers[topic])
return; for (var i = this.observers[topic].length - 1; i >= 0; i--) {
this.observers[topic][i](message)
};
}
} Observable.addObserver('cart', function(message){
console.log("First observer message:" + message)
}) Observable.addObserver('notificatons', function(message){
console.log("Second observer message:" + message)
}) Observable.notifyObservers('cart', 'test 1')
// First observer message:test 1 Observable.notifyObservers('notificatons', 'test 2')
// Second observer message:test 2

相关阅读

javascript-observer-publish-subscribe-pattern

深入理解JavaScript系列(32):设计模式之观察者模式

javascript-patterns-observer

javaScript 设计模式系列之一:观察者模式的更多相关文章

  1. javascript设计模式系列

    javascript设计模式系列   创建型: 1.抽象工厂模式(Abstract Factory) 2.构建者模式(Builder) 3.工厂方法模式(Factory Method) 4.原型模式( ...

  2. 【JavaScript设计模式系列---开篇预览】

    转:http://www.cnblogs.com/Darren_code/archive/2011/08/31/JavascripDesignPatterns.html 2011-08-31 23:5 ...

  3. Javascript设计模式系列三

    继承,一个类或对象继承另一个类或对象的三种方法.类式继承.原型式继承.掺元类. 一.类式继承,原型链.Extend函数. <script type="text/javascript&q ...

  4. Javascript设计模式系列二

    创建对象的基本模式,一.门户大开型,二.采用下划线来表示属性和方法的私用性,三.使用闭包来创建私用的成员. 一.门户大开型.只能提供公用成员.所有属性和方法都公开的.可访问的.这些共用属性都要使用th ...

  5. Javascript设计模式系列一

    定义类,方法赋值给prototype属性各种写法: 方法一: <script type="text/javascript"> ////定义Message类 var Me ...

  6. 【读书笔记】读《JavaScript设计模式》之观察者模式

    一.定义 在事件驱动的环境中,比如浏览器这种持续寻求用户关注的环境中,观察者模式(又名发布者-订阅者(publisher-subscripber)模式)是一种管理人与其任务之间的关系(确切地讲,是对象 ...

  7. 设计模式系列之观察者模式(Observer Pattern)

    意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. 主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作 ...

  8. [转] 浅析JavaScript设计模式——发布-订阅/观察者模式

    前一段时间一直在写CSS3的文章 一直都没写设计模式 今天来写写大名鼎鼎观察者模式 先画张图 观察者模式的理解 我觉得还是发布-订阅模式的叫法更容易我们理解 (不过也有的书上认为它们是两种模式……)  ...

  9. C#设计模式系列:观察者模式(Observer)

    在软件构建过程中,需要为某些对象建立一种“通知依赖关系”,即一个对象的状态发生改变,所有的依赖对象都需要得到通知. 1.观察者模式简介 1.1>.定义 定义对象间的一种一对多的依赖关系,当一个对 ...

随机推荐

  1. 老李分享:SSL协议相关证书

    老李分享:SSL协议相关证书   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:9088214 ...

  2. zoom动画,实现图片点击预览效果

    参考:https://developer.android.google.cn/training/animation/zoom.html 1.创建Views 下面的布局包括了你想要zoom的大版本和小版 ...

  3. 对象的创建过程(chapter5.7.3)

    总结一下对象的创建过程,假设有一个名为Dog的类: 1. 即使没有显示地使用static关键字,构造器实际上也是静态的方法,因此,当首次创建类型为Dog的对象时(构造器可以看成静态方法),或者Dog类 ...

  4. SVN将一台服务器上的代码迁移到另一台服务器上

    由于我们出差,需要把svn服务器上的代码同步到我电脑上,自己各种百度折腾了快一天才弄好,下面来分享下我的具体思路和操作步骤.有2种方式:第一种方式:直接将本地自己dowm下来的代码导入到本地svn服务 ...

  5. JS弹出框

    一.JS三种最常见的对话框 1.alert()警告框      alert是警告框,只有一个按钮"确定"无返回值,警告框经常用于确保用户可以得到某些信息.当警告框出现后,用户需要点 ...

  6. mysql5.7.1.3 安装说明 和出现的问题

    1.可以去官网下载 http://dev.mysql.com/downloads/mysql/ 链接: http://pan.baidu.com/s/1hsO5OX2 密码: jmc6 2.解压到文件 ...

  7. MAT(Memory Analyzer Tool)使用心得

    起因:最近在跟踪产品的性能问题,期间主要问题体现在JVM的内存回收问题,使用MAT工具进行JVM内存分析(也可对android 的应用内存分析) 问题描述: 1.部分后端服务在运行一段时间后会突然年老 ...

  8. 20170410 --- Linux备课资料 --- vim的使用

    首先我们要了解一下什么是vim? -----> vim是从vi发展出来的一个文本编辑器. 那问题又来了,什么是vi呢? ------> vi 是Unix like (可以理解为linux) ...

  9. QQ_MultiTalkServer

    package test_teacher;import java.net.*;import java.io.*;public class MultiTalkServer{    public stat ...

  10. java源码剖析: 对象内存布局、JVM锁以及优化

    一.目录 1.启蒙知识预热:CAS原理+JVM对象头内存存储结构 2.JVM中锁优化:锁粗化.锁消除.偏向锁.轻量级锁.自旋锁. 3.总结:偏向锁.轻量级锁,重量级锁的优缺点. 二.启蒙知识预热 开启 ...