介绍

观察者模式又叫发布订阅模式(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. 老李分享:大数据框架Hadoop和Spark的异同 1

    老李分享:大数据框架Hadoop和Spark的异同   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨 ...

  2. 《ECMAScript标准入门》第二版读书笔记

    title: <ECMAScript标准入门>第二版 date: 2017-04-10 tags: JavaScript categories: Reading-note 2015年6月, ...

  3. Mybatis基础学习(一)—初识MyBatis

    一.MyBatis是什么?      MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google co ...

  4. AOP学习笔记一

    软件开发的目的是为了解决各种需求,包括业务需求和系统需求.目前,业界通过使用面向对象的编程思想,已经可以对业务需求等普通关注点进行很好的抽象与封装,并且使之模块化.但是对于系统需求一类的关注点来说,情 ...

  5. 一些IO流的知识

    IO流: 输入流:输出流: 字节流:字符流:为了处理文字数据方便而出现的对象. 其实这些对象的内部使用的还是字节流(因为文字最终也是字节数据) 只不过,通过字节流读取了相对应的字节数,没有对这些字节直 ...

  6. 第十章 MyBatis入门

    第十章   MyBatis入门10.1 MyBatis入门        优点:简单且功能强大.能够完全控制SQL语句.容易维护和修改    缺点:移植性不好    使用步骤:        1.下载 ...

  7. 看看我做的一款 时间轴 插件 timegliderJs

    TimegliderJs 是一款基于jQuery的时间轴插件.完成后效果. 介绍 Timeglider JS是一个由javascript支持缩放,数据驱动的时间轴组件.非常适合显示项目历史,项目计划及 ...

  8. es5和es6实现lazyman

    es6实现 1 class _LazyMan { constructor(name) { this.tasks = []; this.sleep = this.sleep.bind(this); th ...

  9. 简单介绍关于IOS的生命周期过程

    初步了解一下生命周期的过程: 1.通过alloc init 分配内存,初始化controller. 2.loadViewloadView方法默认实现[super loadView]如果在初始化cont ...

  10. ubuntu 下安装Angular2-cli脚手架

    一.首先需要安装node,npm. 请到nodejs官网进行下载并跟据提示进行安装 版本号中间偶数为稳定版本建议下载 https://nodejs.org/en/ node相关操作 https://n ...