观察模式(Observer)

思想概要

当事件源的管理者根本无法知道事件发生时会有多少,会有哪些处理会被触发时,它最好的选择就是观察模式。这句话的含义很明确,我们要试图建立一个松耦合的架构来处理事件,松耦合常常都是正义的象征,所以此处应该有掌声!观察模式又叫注册/监听模式,这个名字似乎更反映本质,当你对某个信号或者事件感兴趣时,你把某个监听器注册到信号发生源里去,当信号发生时,你就会得到通知,真是言简意赅的描述!

观察模式将信号源的管理类大大的简化了,它无需关注信号发生之外的任何事情,它像一个状态轮询器一样不断的检查自己的状态,并在自己的状态发生变化时,调用观察者列表里的所有的函数即可。当然,高级的观察者模式可以对观察的对象种类做却别处理,但是那并不能算是多复杂的扩展。同时,观察模式也将事件处理的代码分散到了多个观察者类中,每个类都可以是独立,这样的松耦合甚至可以是动态的,因为注册和删除是可以动态完成的,这大大的减轻了代码维护的难度。

观察者模式的类图,ConcreteSubject类作为信号管理类,它负责在发生状态变化时调用notifyObservers函数来通知所有通过addObserver函数注册到自己的观察者们,而观察者们必须提供update函数给信号管理类,以便在notifyObservers中被轮番调用。上图中的update函数是包含参数的,它把整个Subject的引用给传递到了各个观察者类,使得这些观察者类处理事件时可以通过这个引用获取信号管理类里的信息,这也算是反向引用吧。

关于观察者模式,JDK提供了一个较为简单的实现Observable,用它作为实例:

public class Observable {
    private boolean changed = false;
    private Vector<Observer> obs;

    public Observable() {
        obs = new Vector<>();
    }

    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }

    public void notifyObservers() {
        notifyObservers(null);
    }

    public void notifyObservers(Object arg) {
        Object[] arrLocal;

        synchronized (this) {
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }

    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }

    protected synchronized void setChanged() {
        changed = true;
    }

    protected synchronized void clearChanged() {
        changed = false;
    }

    public synchronized boolean hasChanged() {
        return changed;
    }
}

这个类维护了一个Vector来保存外部的观察者,在notifyObservers被调用时查看changed状态,然后决定是否调用观察者们的update函数。

public interface Observer {
    void update(Observable o, Object arg);
}

观察者接口就更简单了,只提供了一个update函数。它接收Observer作为参数,这样似乎可以获取事件发生时的信息。

posted @ 2018-09-10 16:05  Mubawa  阅读(448)  评论(0编辑  收藏  举报