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

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

说起这两个模式确实很像,为了弄懂其中的不同点确实也花了不少功夫,主要参考了这篇博文观察者模式与发布/订阅模式区别,另外一篇就是曾探的《JavaScript设计模式与开发实践》一书中的《发布订阅模式》。两者结合大有所获。

观察者模式

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

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

大致的流向图就像下面。


观察者模式.png

代码如下:

//观察者列表
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中的方法。那么发布订阅模式就可以解耦合,把调用的任务交给一个调度中心(中介),让调度中心去通知各个订阅者。

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

发布订阅模式.png
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就是用于方便取消订阅操作的,假如有一天你租到了自己满意的房子,你就要打电话告诉中介,不要再给我这个号码打电话了,我已经租到房子了。(不然天天都要被中介骚扰了)

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

最后(欢迎大家关注我)

DJL箫氏个人博客
博客GitHub地址
简书
掘金

如果你觉得有所收获的话,欢迎点赞,欢迎到我的github上面star一下。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容