博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
编程模式·观察者模式、事件通知、消息队列三者区别
阅读量:2072 次
发布时间:2019-04-29

本文共 2336 字,大约阅读时间需要 7 分钟。

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

简述和区别

  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们在主线程里。发送消息的可以在其他线程里。

简单总结

需要分层解耦就用事件通知系统。

需要时间解耦就用消息队列

 

转载地址:http://gvvmf.baihongyu.com/

你可能感兴趣的文章
绑定CPU逻辑核心的利器——taskset
查看>>
Linux下perf性能测试火焰图只显示函数地址不显示函数名的问题
查看>>
c结构体、c++结构体和c++类的区别以及错误纠正
查看>>
Linux下查看根目录各文件内存占用情况
查看>>
A星算法详解(个人认为最详细,最通俗易懂的一个版本)
查看>>
利用栈实现DFS
查看>>
(PAT 1019) General Palindromic Number (进制转换)
查看>>
(PAT 1073) Scientific Notation (字符串模拟题)
查看>>
(PAT 1080) Graduate Admission (排序)
查看>>
Play on Words UVA - 10129 (欧拉路径)
查看>>
mininet+floodlight搭建sdn环境并创建简答topo
查看>>
【linux】nohup和&的作用
查看>>
Set、WeakSet、Map以及WeakMap结构基本知识点
查看>>
【NLP学习笔记】(一)Gensim基本使用方法
查看>>
【NLP学习笔记】(二)gensim使用之Topics and Transformations
查看>>
【深度学习】LSTM的架构及公式
查看>>
【python】re模块常用方法
查看>>
剑指offer 19.二叉树的镜像
查看>>
剑指offer 20.顺时针打印矩阵
查看>>
剑指offer 21.包含min函数的栈
查看>>