2. 观察者模式

2021-03-02  本文已影响0人  bit_拳倾天下

什么是观察者模式?

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

其中,被依赖的对象称为主题(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事件监听

上一篇下一篇

猜你喜欢

热点阅读