一、基本概述

不管是观察者模式还是发布订阅者模式,参与角色只有两种,只是他们之间沟通机制不一样;

  1. 观察者模式:观察者模式的两种角色:“观察者和被观察者”,他们之间是直接进行关联,直接通信。所以他们需要知道对方是谁。

javascript开发环境npm javascript开发者_设计模式


2. 发布订阅者模式:该模式也有两种角色:“发布者和订阅者”,他们是通过中间层进行相互通信,并将双方关系进行绑定。这两种角色相互不知道对方是谁。

javascript开发环境npm javascript开发者_javascript开发环境npm_02

总结:观察者模式和发布订阅者作用的目的其实是一样的,只不过他们之间的实现方式不一样。发布订阅者模式相对于观察者模式耦合度更低,因为他们之间不需要直接通信(订阅者只需要告诉中间层他订阅什么内容,而发布者只需要告诉中间层状态);

二、代码实现

1、观察者模式
/**
* ES5版本(建议采用函数表达式进行观察者定义)
* @Function Subject 被观察者函数
* @Function addObserver 添加观察者方法
* @Function delObserver 删除观察者方法
* @Function notify 通知单个观察者
* @Function notifyAll 通知所以观察者
**/
function Subject(){
    //用来管理观察者
    this.observers = [];
}
Subject.prototype = {
    addObserver:function(observer){
        if(this.observers.indexOf(observer) == -1){
            this.observers.push(observer);   
        }
    },
    delObserver:function(observer){
        var _index = this.observers.indexOf(observer);
        if(_index === -1) return;
        this.observers.splice(_index,1);
    },
    notify:function(observer){
        var _index = this.observers.indexOf(observer);
        if(_index === -1) return;
        var msg = "这是给单个观察者的数据";
        this.observers[_index](msg);
    },
    notifyAll:function(){
        var i=0,len=this.observers;
        var msg = "这是给所有观察者的数据";
        for(;i<len;i++){
            this.observers[i](msg);
        }
    }
}
//定义观察者A(函数表单时形式定义观察者)
var observerA = function(msg){
    console.log(msg);
}
//定义观察者B(函数表单时形式定义观察者)
var observerB = function(msg){
    console.log(msg);
}
var sub = new Subject();
sub.addObserver(observerA);
sub.addObserver(observerB);
sub.notify(observerA);  //通知观察者A
sub.notify(observerB);  //通知观察者B
sub.notifyAll();    //通知所有的观察者
/**
* ES6版本(建议采用函数表达式进行观察者定义)
* @Class Subject 被观察者类
* @Function addObserver 添加观察者方法
* @Function delObserver 删除观察者方法
* @Function notify 通知单个观察者
* @Function notifyAll 通知所以观察者
**/
class Subject{
    constructor(){
        this.observers = [];
    }
    addObserver(observer){
        if(this.observers.indexOf(observer) == -1){
            this.observers.push(observer);   
        }
    }
    delObserver(){
        const _index = this.observers.indexOf(observer);
        if(_index === -1) return;
        this.observers.splice(_index,1);
    }
    notify(){
        const _index = this.observers.indexOf(observer);
        if(_index === -1) return;
        const msg = "这是给单个观察者的数据";
        this.observers[_index](msg);
    }
    notifyAll(){
        const msg = "这是给所有观察者的数据";
        this.observers.forEach((observer)=>{
            observer(msg);
        })
    }
}
//定义观察者A(函数表单时形式定义观察者)
const observerA = function(msg){
    console.log(msg);
}
//定义观察者B(函数表单时形式定义观察者)
const observerB = function(msg){
    console.log(msg);
}
const sub = new Subject();
sub.addObserver(observerA);
sub.addObserver(observerB);
sub.notify(observerA);  //通知观察者A
sub.notify(observerB);  //通知观察者B
sub.notifyAll();    //通知所有的观察者
2、发布订阅者模式
//中间层
function Broker(){
    this.subscribers = [];
}
Broker.prototype = {
    addSubscriber:function(subscriber){
        if(this.subscribers.indexOf(subscriber) == -1){
            this.subscribers.push(observer);   
        }
    },
    delSubscriber:function(subscriber){
        var _index = this.subscribers.indexOf(subscriber);
        if(_index === -1) return;
        this.subscribers.splice(_index,1);
    },
    notifyAll:function(msg){
        var i=0,len=this.subscribers;
        for(;i<len;i++){
            this.subscribers[i](msg);
        }
    }
}
//发布者
function Publisher(broker){
    this.broker = broker;
}
Publisher.prototype = {
    notifyAll:function(){
        var msg = "这是给所有订阅者的数据";
        this.broker.notify(msg);
    }
}
//定义订阅者A(函数表单时形式定义订阅者)
const subscriberA = function(msg){
    console.log(msg);
}
//定义订阅者B(函数表单时形式定义订阅者)
const subscriberB = function(msg){
    console.log(msg);
}
//实例化中间层
var brokerObj = new Broker();
brokerObj.addSubscriber(subscriberA);
brokerObj.addSubscriber(subscriberB);
//实例化发布者
var publisherObj = new Publisher(brokerObj);
publisherObj.notifyAll();

说明:ES6版本执行衍生实现

从以上代码可知,“发布订阅者模式”发布者不需要知道订阅者是谁,只需要将消息下发到中间层即可;而“观察者模式”观察者需要知道观察者是谁。所以发布订阅者耦合度更低;

划重点记录:

  1. 为什么用函数表达式声明观察者/订阅者:采用函数表达式形式声明“观察者”和“订阅者”,能够很好的暴露出所属函数,防止重复订阅,取消特定的观察者/订阅者;
  2. 发布订阅者为什么不能通知单个订阅者:上述代码可知,发布订阅者模式相对于观察者模式,少了通知单个订阅者方法(notify方法)。由于发布者和订阅者不知道双方的存在,只通过中间层通信,所以无法知道单个订阅者是谁?自然没有通知单个订阅者的功能。(注意:发布订阅者保持发布者和订阅者的完全不知情性,不要打破这种规则(强制添加通知单个订阅者功能));