設計模式之觀察者模式

        觀察者(Observer)設計模式定義了對象間的一種 一對多的組合關係(一是發佈者,可能是觀察者),以便一個 對象的狀態發生變化時,全部依賴於它的對象都獲得通知並自動刷新【即:信息即時同步】。爲了實現 鬆耦合,觀察者和發佈者之間的互動關係 不是類之間的直接調用[對於觀察者,發佈者只須要知道其實現了某個接口(Oberver接口),至於觀察者究竟是誰,發佈者並不在意]。
 
         本質上,  觀測者模式 = 發佈者 + 觀察者
 
        JDK提供了內置的觀察者模式【java.util.Observable,java.util.Observer】,用戶只須要定義具體的發佈者和觀察者。
 
1. JDK內置的觀察者模式
    1.1 發佈者 : 繼承Obsrevable類,是數據的擁有者。當數據發生更新時,發佈者會通知依賴的觀察者
public class WeatherD extends Observable{

    private double temperature;
    private double humidity;
    private double pressure;
    
    public double getTemperature() {
        return temperature;
    }
    public double getHumidity() {
        return humidity;
    }
    public double getPressure() {
        return pressure;
    }
    
    public void setMeasurements(double temp, double humidity, double pressure){
        this.temperature = temp;
        this.humidity = humidity;
        this.pressure = pressure;
        double[] args = {temp,humidity,pressure};
//註釋一 setChanged();
notifyObservers(args); } }

        1.1.1 註釋一:setChanged()方法將changed狀態置爲true,只有changed狀態置爲true時,在調用notifyObservers()時纔會通知觀察者。setChanged()方法讓你在通知觀察者時具備更多的彈性【在某些場景下,並非發佈者的數據每一次更新都要通知觀察者】。java

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.1.2 能夠調用clearChanged()將changed狀態置爲false,調用hasChanged()查看當前的changed的狀態。設計模式

    1.2  觀察者 : 實現Observer接口,是數據的處理者。從發佈者獲取數據後,觀察者會對數據進行處理
public class ObserverB implements Observer {
    
    private double temperature;
    private double humidity;
    private double pressure;
    
    @Override
    public void update(Observable o, Object arg) {
        //註釋一
//1.push double[] args = (double[]) arg; this.temperature = args[0]; this.humidity = args[1]; this.pressure = args[2]; //2.pull WeatherD d = (WeatherD) o; this.temperature = d.getTemperature(); this.humidity = d.getHumidity(); this.pressure = d.getPressure(); printInfo(); } private void printInfo(){ StringBuilder info = new StringBuilder(); info.append("Current weather date is [temperature : ").append(this.temperature) .append(",humidity : ").append(this.humidity) .append(",pressure : ").append(this.pressure) .append("]."); System.out.println(info.toString()); } }

        1.2.1 註釋一:Java內置的觀察者模式,提供了push(推)和pull(拉)的方式傳遞數據【push:發佈者將全部的數據推送給觀察者;pull:觀察者經過調用發佈者的Getter方法獲取須要的數據】 。(一般認爲,push的方式更正確)app

 

               須要注意的是,Observable是一個類,若是發佈者同時還須要具有另外一個超類的行爲,就會陷入兩難,畢竟Java不支持多繼承,它限制了Observable的複用潛力(而增長複用潛力是模式的原動力)。
ide

               【遇到此類狀況,你能作的就是自定義一套觀察者模式】ui

 

2. 自定義觀察者模式this

           自定義觀察者模式必須具有四個角色:抽象發佈者、具體發佈者、抽象觀察者、具體觀察者。spa

    2.1 抽象發佈者設計

public interface Subject {

    public void registerObserver(Observer o);
    
    public void removeObserver(Observer o);
    
    public void notifyObersers();
}

    2.2 具體發佈者code

        經過接口實現發佈者,避免了沒法繼承其它超類的侷限。可是,也產生了一個新的問題,即:每建立一個觀察者,都必須重寫抽象觀察者的方法。【固然,能夠建立一箇中間層,用來實現抽象發佈者接口,同時繼承其它超類。】server

public class WeatherData implements Subject{

    private double temperature;
    private double humidity;
    private double pressure;
    private List<Observer> observers;
    
    public WeatherData() {
        observers = new ArrayList<Observer>();
    }
    
    public double getTemperature() {
        return temperature;
    }
    public double getHumidity() {
        return humidity;
    }
    public double getPressure() {
        return pressure;
    }
    
    public void setMeasurements(double temp, double humidity, double pressure){
        this.temperature = temp;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsCharged();
    }
    
    private void measurementsCharged(){
        notifyObersers();
    }
    
    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        observers.remove(o);
    }

    @Override
    public void notifyObersers() {
        for (Observer observer : observers) {
            observer.update(temperature, humidity, pressure);
        }
    }
    
}

    2.3 抽象觀察者

public interface Observer {

    public void update(double temp, double humidity, double pressure);

}

    2.4 具體觀察者

public class ObserverA implements Observer {
    
    private double temperature;
    private double humidity;
    private double pressure;

    @Override
    public void update(double temp, double humidity, double pressure) {
        this.temperature = temp;
        this.humidity = humidity;
        this.pressure = pressure;
        printInfo();
    }
    
    private void printInfo(){
        StringBuilder info = new StringBuilder();
        info.append("Current weather date is [temperature : ").append(this.temperature)
            .append(",humidity : ").append(this.humidity)
            .append(",pressure : ").append(this.pressure)
            .append("].");
        System.out.println(info.toString());
    }

}

 

3. 參考資料

    3.1 百度百科:《觀察者模式》

    3.2 O'Reilly:《Head First設計模式》

相關文章
相關標籤/搜索