观察者模式/发布订阅模式

作者: 善倾 | 来源:发表于2018-09-02 00:21 被阅读3次

    在学习 JavaWeb 的监听器的时候,深入思考了下它的实现机制,通过 Google 了解到原来这是利用了观察者模式实现的此功能。故特地来学习了下观察者设计模式,这种方式也叫作发布订阅模式。

    「学习启示」:设计模式这种东西如果没有遇到具体的应用是不会对它有什么深刻理解的,所以对于学习设计模式应该是当遇到了具体的应用实例的时候,再去学习,这时候才是最有效的。最好的方式就是学习 JDK 或者框架源码中的设计模式,一方面能够看到真正的应用,另一方面跟别人讲起来的时候,就显得更有水准,而不是停留在举一个无用的例子的水平。

    到底什么是观察者模式?

    举个生活中的例子吧,每个人或多或少都订阅了一些自己喜欢的微信公众号,每当作者发布一条新的消息的时候,所有订阅者都能够接收得到,观察者模式就是实现的这个功能,当然微信订阅号肯定不是利用这种模式实现的,神似、神似。

    再比如,去医院看专家门诊,也是提前挂号后,然后就一直在门口等待医生通知,医生拿着名单,一个个的叫人进来看病。这就是典型的观察者模式,这个例子中,病人是监听器,医生是被监听对象。

    现在拿 JavaEE 标准类库源码中实际的应用举例,比如 javax.servlet.ServletContextListener 接口就是专门设计来监听 application 对象的,它能够监听 application 对象的创建和销毁过程。awt 事件模型中也利用到了这个设计模式。更多细节请看监听器 Listener 笔记awt 编程

    例子讲到这里,其实就已经能够发现,所谓的监听器只是看起来好像监听器而已,并不是它真的有主动监听的能力,它真正的本质只是一个被动接收事件源发送过来的信息而已。如果事件源不主动把改变信息发送过来,监听器是无法实现监听功能的。

    编码示例

    下面通过实际代码来展示这个过程是怎么实现的,UML 类图如下:

    _观察者模式.png

    信号灯接口如下:

    interface LightsInterface{
        void addListener(LightsListener li);
        void notifyListener(String c);
        void setColor(String c);
    }
    

    信号灯类如下:

    class Lights implements LightsInterface{
        //灯的颜色
        private String color;
        //持久监听器引用
        private List<LightsListener> list = new ArrayList<>();
        //添加监听器
        public void addListener(LightsListener li){
            list.add(li);
        }
        //状态改变了就通知所有监听器
        public void notifyListener(String c){
            for(int i=0;i<list.size();i++){
                LightsListener l = list.get(i);
                l.updateSignal(c);
            }
        }
        //改变灯的颜色
        public void setColor(String c){
            this.color = c;
            //状态改变了就通知监听器(监听器的核心)
            this.notifyListener(c);
        }
    }
    

    信号灯监听器接口如下:

    interface LightsListener{
        void updateSignal(String c);
    }
    

    监听信号灯颜色改变的实现类如下:

    class LightsColorListener implements LightsListener{
        public void updateSignal(String c){
            System.out.println("LightsColorListener update " + c);
        }
    }
    

    主方法测试如下:

    public static void main(String[] args) {
            LightsInterface light = new Lights();
            light.addListener(new LightsColorListener());
            light.addListener(new LightsColorListener());
            light.setColor("red");
        }
    

    从以上的代码实例可以看出,所谓观察者模式,它的本质、核心就是被观察者内部状态发生了改变时,主动将这种信息通过它持有的监听器的引用传递给监听器对象。这个例子弄了接口,只是满足面向接口编程的要求而已,实际应用中可以任意做出改变的,只要最核心的部分没有改变就仍然是观察者模式。

    JavaWeb 中的 application 对象并咩有提供添加监听器的方法,是因为它内部直接持有监听器引用,这只是上述例子的一个变形而已。观察者模式的核心就是被观察者持有监听器的引用,并主动将改变信息告诉监听器对象。所以说,这种模式实现的监听器和电视剧中看到的窃听器还是有本质区别的,不要被误导了,如果是开启一个线程定时主动去查询被观察者的状态信息,得到它的改变,这种才和电视剧中对于监听器的概念是一样的,javax.swing.timer 类可以完成此功能哦。

    相关文章

      网友评论

        本文标题:观察者模式/发布订阅模式

        本文链接:https://www.haomeiwen.com/subject/ahepwftx.html