编程模式·观察者模式、事件通知、消息队列三者区别

观察者模式、事件通知、消息队列三者有类似,都有回调函数注册,通知调用的设计,容易混淆。

简述和区别

  1. 观察者模式:被观察对象状态改变,所有观察它的对象得到通知。也称订阅模式,英文Observer。
    被观察者不依赖观察者,通过依赖注入达到控制反转。
  2. 事件通知:事件发生后,通知所有关心这个事件的对象。
    与观察者模式对比,可理解成所有对象都只依赖事件系统。一半对象观察事件系统,等待特定通知;一半对象状态变化就通过事件系统发出事件。
    观察者也不依赖被观察对象,他只关心事件,不需要到被观察对象那儿注册自己。
    被观察者也只是普通对象,状态改变,通过事件系统发出事件就行了。
  3. 消息队列:将消息排成队列,逐步分发通知。
    与事件通知对比,可理解成事件不是立即通知,而是保存到队列里,稍后通知。
    这个可以达到时间解耦的效果。Windows的消息循环就是一个应用。多线程情况下,消息队列优先于事件系统。

观察者模式

以上课铃声为例子。上课铃声响,同学们回教室。

1. 简单写法

class 上课铃{
    function 响()
        for 学生 in 学生们 do
            学生->回教室()
        end
    end
}

这样写有问题:

  1. 上课铃主动通知学生回教室,依赖关系反了。
  2. 上课铃响,老师要来上课,这个也得上课铃通知,上课铃管的东西太多了。

2. 轮询

class 学生{
    function update()
        if 上课玲响 then
            回教室()
        end
    end
}

这样上课铃只管按时响就行了,也有问题:

  1. 学生的update会越来越复杂,学生还有很多其他事情要做呢。
  2. update太耗时了,学生们,要精神紧张地仔细停玲声有没有响起。

3. 用观察者模式

class 上课铃: Subject{
    function 响()
        NotifyObservers()
    end
}

class 学生: Observer{
    function init()
        上课玲->AddObserver(this.回教室)
    end
    function 回教室() ... end
    function un_init()
        上课玲->RemoveObserver(this.回教室)
    end
}

这样,上课铃只要响的时候发个通知,学生们就等通知好了。老师也类似,等通知就行了。

小结

实际就是注册个回调函数,完美的将观察对象和被观察对象分离。
个人理解:依赖注入,控制反转。观察者依赖被观察者,而不是被观察者依赖观察者。

事件系统

观察者模式有两个问题:

  1. 观察者要获得被观察对象,然后才能注册。
    有时只是要知道某个事件发生了而已,类似网络初始化好了的事件,并不需要获得网络管理对象。
  2. 观察者和被观察者要继承对象的,在单继承体系里,这是很昂贵的一件事。

上课铃的例子里,学生只关心铃声,不关心上课铃这个物体。
用事件模式就可以换个写法

class 事件系统{
    function register(事件类型, handle);
    function remove(事件类型, handle);
    function trigger(事件类型, 数据);
}

class 上课铃{
    function 响()
        事件系统->trigger("上课铃声")
    end
}

class 学生{
    function init()
        事件系统->register("上课铃声", this->回教室)
    end
    function 回教室() ... end
    function un_init()
       事件系统->remove("上课铃声", this.回教室)
    end
}

小结

事件通知系统用的很广泛的。很多代码会有个EventDispatcherEventControl之类的类。
特别是UI程序,当数据发生变化时通知相关UI更新。
观察者模式可以做到,但是事件通知来实现会更加简单。

消息队列

消息队列和事件系统很像。但是消息队列不是立即通知,而是把消息先放到队列里再通知。
上课铃的例子

class 消息队列{
    function register(消息类型, handle);
    function remove(消息类型, handle);
    function sendMsg(消息);
    function process();
}

class 上课铃{
    function 响()
        消息队列->sendMsg("上课铃声")
    end
}

class 学生{
    function init()
        消息队列->register("上课铃声", this->回教室)
    end
    function 回教室() ... end
    function un_init()
        消息队列->remove("上课铃声", this.回教室)
    end
}

main{
    while(有消息) do
        消息队列->process()
    end
}

从伪代码也可以看出,消息队列和事件系统的使用基本是一样的。如果消息队列不延后处理,就是事件系统了。
消息队列可以用于多线程,接受处理消息的handle们在主线程里。发送消息的可以在其他线程里。

简单总结

需要分层解耦就用事件通知系统。
需要时间解耦就用消息队列。

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

推荐阅读更多精彩内容