设计模式之观察者模式

介绍

观察者模式是软件设计模式的一种。在此种模式中,一个目标对象维持一系列依赖于它(观察者)的对象将有关状态的任何更新自动通知给他们。

观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。

使用观察者模式的好处:

1支持简单的广播通信,自动通知所有已经订阅过的对象。方便各种状态的管理。

2页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。

3目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。

实现方式

观察者模式有很多实现方式,从根本上说,该模式必须包含两个角色:观察者和目标目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口。具体观察者和具体目标继承各自的基类,然后具体观察者把自己注册到具体目标里,在具体目标发生变化时候,调度观察者的更新方法。

 

具体实现代码:

if (!Array.prototype.forEach) {
    Array.prototype.forEach = function (fn, thisObj) {
        var scope = thisObj || window;
        for (var i = 0, 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 = 0, j = this.length; i < j; ++i) {
            if (!fn.call(scope, this[i], i, this)) {
                continue;
            }
            a.push(this[i]);
        }
        return a;
    };
  }

  //扩展函数扩展对象
  function extend(obj, extension){
    for(var key in obj){
      extension[key] = obj[key]
    }
  }

   //观察者目标
   function ObserverSubject(){
    this.observerList = [];
   }

   ObserverSubject.prototype.addObserver = function(observer){
     this.observerList.push(observer)
   };

   ObserverSubject.prototype.removeObserver = function(observer){
    this.observerList = this.observerList.filter(function(el) {
      return el !== observer
    });
   }

    ObserverSubject.prototype.notify = function(context){
      this.observerList.forEach(function(el, index) {
        el.update(context)
      });
    }

   //观察者对象
   function Observer() {
    this.update = function(content){

    }
   }


   var observerSubjectIns = {};

   extend(new ObserverSubject(),observerSubjectIns)

   var ob1 = new Observer();

  ob1.update = function(content){
    console.log('ob1 收到通知:' + content)
  }

   var ob2 = new Observer();

  ob2.update = function(content){
    console.log('ob2 收到通知:' + content)
  }

  observerSubjectIns.addObserver(ob1);
  observerSubjectIns.addObserver(ob2);
  observerSubjectIns.notify('吃饭');

  observerSubjectIns.removeObserver(ob2);
  observerSubjectIns.notify('吃饭');

发布(Publish/订阅(Subscribe)模式的的区别

在很多地方,包括百度百科中,都把观察者(Observer)模式等同于发布(Publish/订阅(Subscribe)模式

两者都在功能上都实现广播通知,但是两者还是存在着差异。我们先来看发布(Publish/订阅(Subscribe)模式的定义

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

 

代码实现

var pubsub = {};
  (function(q){
    var topics = {},
        subUid = -1;
    //发布广播事件
    q.publish = function(topic,args){
      if(!topics[topic]){
        return false;
      }

      var subscribers = topics[topic],
          length = subscribers.length;

      while(length --){
        subscribers[length].func(args);
      }
    }
    //通过特定的名称和回到函数订阅事件
    q.subscribe = function(topic,func){
        if(!topics[topic]){
          topics[topic] = [];
        }

        var token = (++subUid).toString();
         topics[topic].push({
          token : token,
          func: func
        })

        return token;
    }
    //通过特定的引用取消订阅
    q.unsubscribe = function(token){
      for(var m in topics){
        var item = topics[m]
        if(item){
          for(var i = 0 , length = item.length ; i < length ; ++ i){
            if(item[i].token === token){
              item.splice(i, 1);
              return token;
            }
          }
        }
      }
      return this;
    }
  })(pubsub)

  var sub1 = pubsub.subscribe('reader',function(content){
    console.log('小明订阅购买' + content)
  })

  var sub2 = pubsub.subscribe('reader',function(content){
    console.log('小红订阅购买' + content)
  })

  var sub3 = pubsub.subscribe('daily',function(content){
    console.log('小红订阅购买' + content)
  })

   pubsub.publish('reader','读者')

   pubsub.unsubscribe(sub1);

   pubsub.publish('reader','读者')
   pubsub.publish('daily','日报')

我们举个例子:

订阅刊物,我们有两种形式,一种方式是我们直接向刊物的发行单位订阅,这时候,我们需要知道这个发行单位,发行单位同时也必须知道读者,这样才能在在新一期的刊物发行的时候送到读者手里。

另外一种方式,我们直接向附近的报刊亭订阅。这种方式我们不需要关注发行单位,同时发行单位也不必知道订阅者是谁。当新一期刊物发行后,直接送到报刊亭,再由报刊亭统一的送达到读者手上。

第一种方式就是观察者模式,而第二种方式就是发布/订阅模式

总结

虽然两种模式都存在订阅者和发布者(具体观察者可认为是订阅者、具体目标可认为是发布者),但是观察者模式是由具体目标调度的,而发布/订阅模式是统一由调度中心调的,所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会。

 

posted @ 2017-05-02 18:38  CaiBoBo  阅读(403)  评论(0编辑  收藏  举报