zoukankan      html  css  js  c++  java
  • 设计模式15---观察者模式(Observer Pattern)

    一、观察者模式定义

    观察者模式定义:
    Define a one-to-many dependency between objects so that when one object changes state, all its dependents aer notified and updated automatically.
    定义对象间一种一对多的依赖关系,使得当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

         

      如上图所示(截取自《Head First Design Patterns》一书),主要包括四个部分:

      1. Subject被观察者。是一个接口或者是抽象类,定义被观察者必须实现的职责,它必须能偶动态地增加、取消观察者,管理观察者并通知观察者。

      2. Observer观察者。观察者接收到消息后,即进行update更新操作,对接收到的信息进行处理。

      3. ConcreteSubject具体的被观察者。定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。

      4. ConcreteObserver具体观察者。每个观察者在接收到信息后处理的方式不同,各个观察者有自己的处理逻辑。

    二、观察者模式优势

    观察者和被观察者之间是抽象耦合的,不管是增加观察者还是被观察者都非常容易扩展。

    根据单一职责原则,每个类的职责是单一的,那么怎么把各个单一的职责串联成真实的复杂的逻辑关系呢,观察者模式可以起到桥梁作用。
    观察者模式是松耦合的典型。

      在Android源码中,其中一个经典的使用到观察者模式的就是Android控件的事件监听模型。

    三、观察者模式的实例

    1、定义一个抽象被观察者接口

    复制代码
    package com.linghu.observer;
    
    /***
     * 抽象被观察者接口
     * 声明了添加、删除、通知观察者方法
     * @author linghu
     *
     */
    public interface Observerable {
        
        public void registerObserver(Observer o);
        public void removeObserver(Observer o);
        public void notifyObserver();
        
    }

     2、定义一个抽象观察者接口

    复制代码
    package com.linghu.observer;
    
    /***
     * 抽象观察者
     * 定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。
     * @author linghu
     *
     */
    public interface Observer {
        public void update(String message);
    }
    复制代码

    3、定义被观察者,实现了Observerable接口,对Observerable接口的三个方法进行了具体实现,同时有一个List集合,用以保存注册的观察者,等需要通知观察者时,遍历该集合即可。

    复制代码
    package com.linghu.observer;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 被观察者,也就是微信公众号服务
     * 实现了Observerable接口,对Observerable接口的三个方法进行了具体实现
     * @author linghu
     *
     */
    public class WechatServer implements Observerable {
        
        //注意到这个List集合的泛型参数为Observer接口,设计原则:面向接口编程而不是面向实现编程
        private List<Observer> list;
        private String message;
        
        public WechatServer() {
            list = new ArrayList<Observer>();
        }
        
        @Override
        public void registerObserver(Observer o) {       
            list.add(o);
        }
        
        @Override
        public void removeObserver(Observer o) {
            if(!list.isEmpty())
                list.remove(o);
        }
    
        //遍历
        @Override
        public void notifyObserver() {
            for(int i = 0; i < list.size(); i++) {
                Observer oserver = list.get(i);
                oserver.update(message);
            }
        }
        
        public void setInfomation(String s) {
            this.message = s;
            System.out.println("微信服务更新消息: " + s);
            //消息更新,通知所有观察者
            notifyObserver();
        }
    
    }
    复制代码

    4、定义具体观察者,微信公众号的具体观察者为用户User

    复制代码
    package com.linghu.observer;
    
    /**
     * 观察者
     * 实现了update方法
     * @author linghu
     *
     */
    public class User implements Observer {
        private String name;
        private String message;
        
        public User(String name) {
            this.name = name;
        }
        
        @Override
        public void update(String message) {
            this.message = message;
            read();
        }
        
        public void read() {
            System.out.println(name + " 收到推送消息: " + message);
        }
        
    }

    5、编写一个测试类

    首先注册了三个用户,ZhangSan、LiSi、WangWu。公众号发布了一条消息"PHP是世界上最好用的语言!",三个用户都收到了消息。

    用户ZhangSan看到消息后颇为震惊,果断取消订阅,这时公众号又推送了一条消息,此时用户ZhangSan已经收不到消息,其他用户

    还是正常能收到推送消息。

    复制代码
    package com.linghu.observer;
    
    public class Test {
        
        public static void main(String[] args) {
            WechatServer server = new WechatServer();
            
            Observer userZhang = new User("ZhangSan");
            Observer userLi = new User("LiSi");
            Observer userWang = new User("WangWu");
            
            server.registerObserver(userZhang);
            server.registerObserver(userLi);
            server.registerObserver(userWang);
    server.setInfomation("PHP是世界上最好用的语言!"); System.out.println("----------------------------------------------"); server.removeObserver(userZhang);
    server.setInfomation("JAVA是世界上最好用的语言!"); }
    }

    四、观察者模式在Android源码中的应用

      1. 看View类源代码中的OnKeyListener接口:

    复制代码
        /**
         * Interface definition for a callback to be invoked when a key event is
         * dispatched to this view. The callback will be invoked before the key
         * event is given to the view.
         */
        public interface OnKeyListener {
            /**
             * Called when a key is dispatched to a view. This allows listeners to
             * get a chance to respond before the target view.
             *
             * @param v The view the key has been dispatched to.
             * @param keyCode The code for the physical key that was pressed
             * @param event The KeyEvent object containing full information about
             *        the event.
             * @return True if the listener has consumed the event, false otherwise.
             */
            boolean onKey(View v, int keyCode, KeyEvent event);
        }

      2. 再看View类定义了私有成员mOnKeyListener(通过组合的方式):

    private OnKeyListener mOnKeyListener;

      3. 注册listener

    复制代码
        /**
         * Register a callback to be invoked when a key is pressed in this view.
         * @param l the key listener to attach to this view
         */
        public void setOnKeyListener(OnKeyListener l) {
            mOnKeyListener = l;
        }

      4. 剩下的就交给开发者自己构造外部观察者对象与该按键的事件接口进行绑定,获取事件消息。

      最后让我们记住支撑“观察者模式”的设计原则: Strive for loosely coupled designs between objects that interact.

  • 相关阅读:
    【iOS开发每日小笔记(十二)】仿Facebook登录界面 错误提示抖动 利用CAAnimation设置动画效果
    《跑酷好基友》(英文名:BothLive)隐私政策声明
    【iOS开发每日小笔记(十一)】iOS8更新留下的“坑” NSAttributedString设置下划线 NSUnderlineStyleAttributeName 属性必须为NSNumber
    【iOS开发每日小笔记(十)】自制带圆框的头像 利用在CALayer设置“寄宿图”
    【iOS开发每日小笔记(九)】在子线程中使用runloop,正确操作NSTimer计时的注意点 三种可选方法
    2018/3/29
    2018/3/26
    2018/3/25
    BZOJ[3091] 城市旅行
    2018/3/23
  • 原文地址:https://www.cnblogs.com/linghu-java/p/5728407.html
Copyright © 2011-2022 走看看