zoukankan      html  css  js  c++  java
  • 编程模式·观察者模式、事件通知、消息队列三者区别

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

    2017.01.11 19:07:09字数 1050阅读 2016

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

    简述和区别

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

    简单总结

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

  • 相关阅读:
    CF 461B Appleman and Tree
    POJ 1821 Fence
    NOIP 2012 开车旅行
    CF 494B Obsessive String
    BZOJ2337 XOR和路径
    CF 24D Broken robot
    POJ 1952 BUY LOW, BUY LOWER
    SPOJ NAPTIME Naptime
    POJ 3585
    CF 453B Little Pony and Harmony Chest
  • 原文地址:https://www.cnblogs.com/grj001/p/12223629.html
Copyright © 2011-2022 走看看