JS设计模式2-发布/订阅模式和观察者模式

发布(Publish)/订阅(Subscribe)模式是一种和观察者(Observer)模式很相似的设计模式,以至于很多人把这两种模式看作是同一种模式。

在观察者模式中的Subject就像一个发布者(Publisher),而观察者(Observer)完全可以看作一个订阅者(Subscriber)。subject通知观察者时,就像一个发布者通知他的订阅者。


1.观察者模式和发布/订阅模式的概念
  • 观察者模式
    目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口。具体观察者和具体目标继承各自的基类,然后具体观察者把自己注册到具体目标里,在具体目标发生变化时候,调度观察者的更新方法。

    observer.png

  • 发布/订阅模式
    订阅者把自己想订阅的事件注册到调度中心,当该事件触发时候,发布者发布该事件到调度中心(顺带上下文),由调度中心统一调度订阅者注册到调度中心的处理代码。

    pubsub.png

我们再用一个图来直观地感受一下两种模式之间的区别:

common.jpg

观察者模式和发布/订阅模式的区别是:

    1. 从上面的图片中可以看到,最大的区别是调度的地方。虽然两种模式都存在订阅者和发布者(具体观察者可认为是订阅者、具体目标可认为是发布者),但是观察者模式是由具体目标调度的,而发布/订阅模式是统一由调度中心调的,所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会。
    1. 在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。

2.观察者模式实现

下面这段代码摘抄自JavaScript 设计模式一书

  • 2.1对观察者和被观察者进行建模:


    2-1.png
  • 2.2 扩展函数
function extend(extension,obj){ 
   for(var key in extension){
   obj[key]=extension[key]; }
}
  • 2.3使用范例
html:
<button id="addNewObserver">Add New Observer checkbox</button>
<input id="mainCheckbox" type="checkbox"/>
<div id="observersContainer"></div>

script:
//注意要把2-1和2-2封装好的函数copy进来
//我们DOM元素的引用
var controlCheckbox=document.getElementById("mainCheckbox"), 
      addBtn=document.getElementById("addNewObserver"), 
      container=document.getElementById("observersContainer");

//具体的被观察者 //Subject类扩展controlCheckbox类
extend(new Subject(),controlCheckbox); 
//点击checkbox将会触发对观察者的通知
controlCheckbox["onclick"]=new Function("controlCheckbox.notify(controlCheckbox.checked)");

addBtn["onclick"]=AddNewObserver; 

//具体的观察者
 function AddNewObserver(){
   //建立一个新的用于增加的checkbox
    var check =document.createElement("input"); check.type="checkbox";
   //使用Observer类扩展
    extend(new Observer(),check);
   //使用定制的Update函数重载 
    check.update=function(value){
      this.checked=value; 
    };

//增加新的观察者到我们主要的被观察者的观察者列表中
controlCheckbox.addObserver(check);

//将元素添加到容器的最后
container.appendChild(check); 
}

运行结果截图:


observer-res.png

3.发布/订阅模式实现

发布/订阅在JavaScript的生态系统中非常合适,主要是因为作为核心的ECMAScript 实现是事件驱动的。尤其是在浏览器环境下更是如此,因为DOM 使用事件作为其主要的用于脚本的交互API。


pubsub.png
  • 测试
 var messageLogger=function(topics,data){
    console.log("Logging:"+topics+":"+data);
 };


var subscription=pubsub.subscribe("inbox/newMessage",messageLogger);

pubsub.publish("inbox/newMessage","helloworld!"); 
// or
pubsub.publish("inbox/newMessage",["test","a","b","c"]);
// or
pubsub.publish("inbox/newMessage",{
  sender:"hello@google.com",
  body:"Heyagain!"
});

  • 运行结果


    pubsub-res.png

关于发布/订阅模式的渐进实现大家可以参考JS设计模式之订阅模式


参考文章:
观察者模式与发布/订阅模式区别
【Javascript设计模式3】-观察者模式
《JavaScript 设计模式》一书

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容