设计模式学习之观察者模式和发布订阅模式

要说起学习设计模式的动机实际上是为了准备面试,惭愧脸,但是也正是因为要面试所以促使我去学习,今天学习的就是观察者模式和发布订阅模式。

观察者模式

首先来谈谈观察者模式,在观察者模式中,有两个角色一个是Subject,用来维护一个observer列表,另一个角色就是Observer(观察者),在Observer中定义了一个具体的update方法,用来执行相关操作。整个过程就是当某个值发生变化后,Subject调用notify方法(实际就是循环调用observerList中每个observer的update方法,并把新的值作为update的参数传递进去)。从中我们可以看出在Subject中直接调用了Observer中的方法,也就是说Subject和Observer的联系实际上是非常紧密的。

举个例子,现在有一个房东他要租房子,当有空房子的时候,他就会去通知曾经来询问的租户,那么这个时候房东就是直接知道租客的电话和需求(要住什么样的房子)的,也就是此时房东和租客之间实际上是存在联系的。

大致的流向图就像下面。

代码如下:

//观察者列表
function ObserverList(){
  this.observerList = [];
}
ObserverList.prototype.add = function( obj ){
  return this.observerList.push( obj );
};
ObserverList.prototype.count = function(){
  return this.observerList.length;
};
ObserverList.prototype.get = function( index ){
  if( index > -1 && index < this.observerList.length ){
    return this.observerList[ index ];
  }
};
ObserverList.prototype.indexOf = function( obj, startIndex ){
  var i = startIndex;
  while( i < this.observerList.length ){
    if( this.observerList[i] === obj ){
      return i;
    }
    i++;
  }
  return -1;
};
ObserverList.prototype.removeAt = function( index ){
  this.observerList.splice( index, 1 );
};

//目标
function Subject(){
  this.observers = new ObserverList();
}
Subject.prototype.addObserver = function( observer ){
  this.observers.add( observer );
};
Subject.prototype.removeObserver = function( observer ){
  this.observers.removeAt( this.observers.indexOf( observer, 0 ) );
};
Subject.prototype.notify = function( context ){
  var observerCount = this.observers.count();
  for(var i=0; i < observerCount; i++){
    this.observers.get(i).update( context );
  }
};

//观察者
function Observer(){
  this.update = function(){
    // ...
  };
}

 

发布订阅模式

前面说到Subject和Observer联系是非常紧密的,因为我们要在Subject中调用Observer中的方法。那么发布订阅模式就可以解耦合,把调用的任务交给一个调度中心(中介),让调度中心去通知各个订阅者。

接着上面的例子。房东有钱后,自己变懒了,他不想每次有房源后,自己还要亲自打电话通知之前预留电话想要租房的租客,因为自己还要记住那些的租客的电话和需求(有钱了不想干这些活,我要躺着赚钱)。于是他就找到了中介,每次空出房子后,直接告诉中介我这里有什么样的房子,中介这里记录着哪些租客有着什么样的需求,中介再去联系有这样需求的租客。那么这里房东和未来可能的租客之间是没有联系的,房东从此不用自己再去亲自打电话去通知每一个有着这样需求的租客,只需要告诉中介一个人就行,中介去通知。那么整个过程就如下面这样

var pubsub = {};
(function(myObject) {
    // Storage for topics that can be broadcast
    // or listened to
    var topics = {};
    // An topic identifier
    var subUid = -1;
    // Publish or broadcast events of interest
    // with a specific topic name and arguments
    // such as the data to pass along
    myObject.publish = function( topic, args ) {
        if ( !topics[topic] ) {
            return false;
        }
        var subscribers = topics[topic],
            len = subscribers ? subscribers.length : 0;
        while (len--) {
            subscribers[len].func( topic, args );
        }
        return this;
    };
    // Subscribe to events of interest
    // with a specific topic name and a
    // callback function, to be executed
    // when the topic/event is observed
    myObject.subscribe = function( topic, func ) {
        if (!topics[topic]) {
            topics[topic] = [];
        }
        var token = ( ++subUid ).toString();
        topics[topic].push({
            token: token,
            func: func
        });
        return token;
    };
    // Unsubscribe from a specific
    // topic, based on a tokenized reference
    // to the subscription
    myObject.unsubscribe = function( token ) {
        for ( var m in topics ) {
            if ( topics[m] ) {
                for ( var i = 0, j = topics[m].length; i < j; i++ ) {
                    if ( topics[m][i].token === token ) {
                        topics[m].splice( i, 1 );
                        return token;
                    }
                }
            }
        }
        return this;
    };
}( pubsub ));

 

这里为什么要用一个立即执行函数传递一个对象进去,因为我们可能有多个中介,每多一个中介,我们都会动态的去添加一些方法(即告诉中介如何去运作)。subUid就是用于方便取消订阅操作的,假如有一天你租到了自己满意的房子,你就要打电话告诉中介,不要再给我这个号码打电话了,我已经租到房子了。(不然天天都要被中介骚扰了)

总结:观察者模式和发布订阅模式的区别应该就是当有房源消息的时候,到底是谁来通知租客,观察者是房东自己本人,而发布订阅则是中介。

如果大家想学习前端方面的技术,我把我多年的经验分享给大家,还有一些学习资料,分享Q群:1046097531

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值