• 设计模式之观察者模式


    介绍

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

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

    使用观察者模式的好处:

    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','日报')

    我们举个例子:

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

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

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

    总结

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

  • 相关阅读:
    E. XOR and Favorite Number (莫队板子题)
    bzoj 2038: [2009国家集训队]小Z的袜子(hose)
    世风日下的哗啦啦族I (简单分块模板)
    Turtles (非纯分块)
    楼房重建
    智商问题
    A
    51 Nod 1640 天气晴朗的魔法( Kruskall )
    后缀数组
    51nod 1562 玻璃切割 (set)
  • 原文地址:https://www.cnblogs.com/caizhenbo/p/6782492.html
Copyright © 2020-2023  润新知