美文网首页
2. 观察者模式

2. 观察者模式

作者: bit_拳倾天下 | 来源:发表于2021-03-02 10:22 被阅读0次

    什么是观察者模式?

    定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖都会收到通知并能够自动更新。

    其中,被依赖的对象称为主题(Subject),依赖的对象称为观察者(Observer)。简单点说:Subject 中维护了一个 Observer 的列表,每当有 Observer 订阅,就会被添加到这个列表,有 Observer 取消订阅,这个 Observer 就会被删除。当 Subject 状态发生改变时,就会遍历 Observer 列表,进行通知。订阅、取消订阅的时机以及触发改变的条件,根据业务逻辑而定。通知时,Observer 是用拉还是由 Subject 推,也根据实际需求定。

    动手实现:

    //Subject 接口
    public interface Subject {
        void addObserver(Observer observer);
        void deleteObserver(Observer observer);
        void notifyObservers();
        void notifyObservers(Object data);
    }
    
    //Subject 实现
    public class Publisher implements Subject {
        private List<Observer> observers = new ArrayList<>();
        private String msg;
        private String status;
        @Override
        public void addObserver(Observer observer) {
            observers.add(observer);
        }
    
        @Override
        public void deleteObserver(Observer observer) {
            if(observers.contains(observer)){
                observers.remove(observer);
            }
        }
    
        /**
         * 拉数据
         */
        @Override
        public void notifyObservers() {
            notifyObservers(null);
        }
    
        /**
         * 推数据
         * @param data
         */
        @Override
        public void notifyObservers(Object data) {
            observers.forEach(observer -> observer.updateData(this, data));
        }
    
        public String getMsg() {
            return msg;
        }
    
        /**
         * 模拟状态变化, 拉数据
         * @param msg
         */
        public void setMsg(String msg) {
            this.msg = msg;
            notifyObservers();
        }
    
        public String getStatus() {
            return status;
        }
    
        /**
         * 模拟状态变化,推数据
         * @param status
         */
        public void setStatus(String status) {
            this.status = status;
            notifyObservers(status);
        }
    }
    
    
    //Observer接口
    public interface Observer {
        void updateData(Subject subject,Object data);
    }
    
    //Observer实现
    public class Subscriber1 implements Observer {
    
        @Override
        public void updateData(Subject subject, Object data) {
            if(StringUtils.isEmpty(data)){
                if(subject instanceof Publisher){
                    Publisher publisher = (Publisher)subject;
                    System.out.println("观察者1 收到信息(拉):" + publisher.getMsg() + "---" + publisher.getStatus());
                }
            }else{
                System.out.println("观察者1 收到信息(推):" + data);
            }
        }
    }
    
        //测试类
        @Test
        void contextLoads() {
            Publisher publisher = new Publisher();
            Subscriber1 subscriber1 = new Subscriber1();
            Subscriber2 subscriber2 = new Subscriber2();
    
            publisher.addObserver(subscriber1);
            publisher.addObserver(subscriber2);
    
            publisher.setMsg("123");
            publisher.setStatus("发送");
        }
    

    运行测试类的结果:

    观察者1 收到信息(拉):123---null
    观察者2 收到信息(拉):123---null
    观察者1 收到信息(推):发送
    观察者2 收到信息(推):发送

    JDK 实现

    这种模式 JDK 已经分装好了,分别是Observable类、Observer接口,原理和上面类似,但是多了一个 changed 属性,可以控制通知观察者的条件,例如:人数统计,每满100人次通知一次,避免通知过于频繁。

        public void notifyObservers(Object arg) {
            /*
             * a temporary array buffer, used as a snapshot of the state of
             * current Observers.
             */
            Object[] arrLocal;
    
            synchronized (this) {
                /* We don't want the Observer doing callbacks into
                 * arbitrary code while holding its own Monitor.
                 * The code where we extract each Observable from
                 * the Vector and store the state of the Observer
                 * needs synchronization, but notifying observers
                 * does not (should not).  The worst result of any
                 * potential race-condition here is that:
                 * 1) a newly-added Observer will miss a
                 *   notification in progress
                 * 2) a recently unregistered Observer will be
                 *   wrongly notified when it doesn't care
                 */
                if (!changed)
                    return;
                arrLocal = obs.toArray();
                clearChanged();
            }
    
            for (int i = arrLocal.length-1; i>=0; i--)
                ((Observer)arrLocal[i]).update(this, arg);
        }
    

    总结

    1. 订阅者与被订阅者松耦合
    2. 一旦被订阅者发生改变,订阅者能立马收到通知

    典型应用

    Websockt
    JBotton事件监听

    相关文章

      网友评论

          本文标题:2. 观察者模式

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