设计模式-观察者模式(Java实现)

1. 摘要

观察者模式可以完美地将观察者和被观察者对象分开[1]。观察者模式,类似于订阅-发布模型:如报社提供报纸订阅的服务,居民购买报纸订阅的服务。报社和居民并不需要直接认识对方。但订阅报纸的居民,每天都能收到报社发布的日报。


2. 观察者模式UML图

设计模式-观察者模式(Java实现)_第1张图片


Observer即订阅者的interface,Observable即订阅主题的抽象类。Observable(订阅主题)内通过List来存储Observer(订阅者)的引用。当Observable(订阅主题)有变化时,调用Observable(订阅主题)的notify()方法,即可让所有的Observer(订阅者)收到通知。

如果ConcreteObservable是报社,那么Observer就是订阅报纸的居民。


3. 观察者模式实现

Observer:

public interface Observer {
    void update(String msg);
}


Observable:

public abstract class Observable {

    private List mObserverList = new ArrayList<>();

    public final void attach(Observer observer) {
        mObserverList.add(observer);
    }

    public final void detach(Observer observer) {
        mObserverList.remove(observer);
    }

    protected void notify(String msg) {
        for (Observer observer : mObserverList) {
            observer.update(msg);
        }
    }
}


ConcreteObserver:

public class ConcreteObserver implements Observer {
    @Override
    public void update(String msg) {
        System.out.println("ConcreteObserver updage() msg: " + msg);
    }
}

ConcreteObservable:

public class ConcreteObservable extends Observable {

    private String mMsg;

    public String getMsg() {
        return mMsg;
    }

    public void setMsg(String msg){
        mMsg = msg;
        notify(msg);
    }
}

Client:

public class Client {
    public static void main(String args[]) {
        ConcreteObservable paper = new ConcreteObservable();

        ConcreteObserver resident0 = new ConcreteObserver();
        ConcreteObserver resident1 = new ConcreteObserver();

        paper.attach(resident0);
        paper.attach(resident1);

        paper.setMsg("papaer is sent");
    }
}


执行结果:

ConcreteObserver updage() msg: papaer is sent
ConcreteObserver updage() msg: papaer is sent


4. Java自带的观察者模式

Java本身自带的观察者模式为:java.util.Observable和java.util.Observer。其基本原理,与之前实现的相似,但有很多细节,非常值得学习。


java.util.Observer:

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

java.util.Observer为一个接口,但它的通用性,比刚才实现的Observer要强大很多。Observable o可以告诉Observer,具体是哪个Observable发生了变化。Object arg可以传递任何类型的参数。


java.util.Observable:

public class Observable {
    // 判断Observable是否有变化
    private boolean changed = false;
    // 存储订阅者的引用
    private Vector 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();
    }

    // 设置changed为true
    protected synchronized void setChanged() {
        changed = true;
    }

    // 设置changed为false
    protected synchronized void clearChanged() {
        changed = false;
    }

    // 检查changed是否为true
    public synchronized boolean hasChanged() {
        return changed;
    }

    // 获取订阅者数量
    public synchronized int countObservers() {
        return obs.size();
    }
}

可以看到,java.util.Observable使用的是Vector来存储Observers,很多方法都使用了“synchronized”关键字,保证了java.util.Observable的线程安全。通过changed的属性使用,使得notifyXXX被调用时,如果Observable并未真正发生变化时,Observer不会收到通知。


5. 自实现观者者模式 VS Java自带观察者模式

java.util.Observable和java.util.Observer的使用方式,与之前自己实现的Observable和Observer的使用方式,基本一样。除了以下两点:

(A) java.util.Observer可以得知发生变化的java.util.Observable具体类,而且,可传任意类型的参数。

(B) java.util.Observable需要通过setChanged()和clearChaged()来维护Observable具体类,是否真的发生了变化。


具体使用方式,就不再累述。使用有困难的同学,可以留言,大家一起讨论一下。


6. 引用

[1] 观察者模式_百度百科

你可能感兴趣的:(设计模式(Java))