設計模式之觀察者模式(Java)

  設計模式(Design pattern)是什麼?它是一套由四人組(The Gang of Four, [1]的做者)總結出來的軟件設計框架。其目的是爲了提升代碼的可重用性,加強系統的可維護性和代碼的易讀性。在四人組的《Design Patterns》一書中提到了23中最經常使用的設計模式,大體能夠分爲三大類:
  1. 建立型模式,共5種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式;
  2. 結構型模式,共7種:適配器模式、裝飾器模式、代理模式、外觀模式、橋鏈接模式、組合模式、享元模式;
  3. 行爲型模式,共11種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。

  關於上面23中設計模式的大概介紹能夠參考博客[2]。java

  從上面的分類能夠看出觀察者模式是一種對象的行爲型模式。它也被稱之爲發佈-訂閱(Publish-Subscribe)模式、模型視圖(Model-View)模式或源-監聽器(Source-Listener)模式[3]。通俗的說,觀察者模式涉及到(至少)兩個對象。其一是觀察者,其二是被觀察者。例如在一個RSS訂閱系統中,發佈方充當被觀察者角色,而訂閱方則充當了觀察者角色。通常來講,觀察者與被觀察者是多對一的關係。即多個監聽器能夠同時監聽某一主題對象。當主題對象狀態發生改變時,監聽器對象也會自動的更新自身狀態。
 
   這篇博客主要是從一個實際的例子出發,來簡單的說明Java(Android)、Objective-C(iOS)、C#(Windows Phone)三種面向對象編程語言對觀察者模式的實現。
 

觀察者模型實例之燒開水

  從一個燒開水的例子出發。如今咱們有個熱水器,咱們用它來燒開水。在燒水的過程當中,顯示器和揚聲器都一直監視水溫。顯示器將水溫顯示在顯示屏上。另外,當水溫超過90度時,揚聲器開始發出警告,提示水快燒開。編程

Java實現

  Java對觀察者類的支持,主要體如今Observable類和Observer接口。設計模式

1. java.util.Observable類 = 被觀察者

Observable類的主要方法:框架

public class Observable {
    void setChanged(); //設置被觀察者的狀態已經被改變
    void clearChanged(); //清除被觀察者狀態的改變,此時再調用hasChanged()將返回false
    void addObserver(Observer observer);
    int countObservers();
    void deleteObserver(Observer observer);
    void deleteObservers();
    boolean hasChanged();
    void notifyObservers();
    void notifyObservers(Object arg); // 參數通常設定爲被改變的屬性
}

熱水器類繼承自Observerable類,做爲一種具體的被監控對象:編程語言

public class Heater extends Observable {
    private int temperature;

    // get方法,返回水溫
    public int getTemperature(){
        return temperature;
    }

    // set方法,設置水溫
    public void setTemperature(int temperature){
        this.temperature = temperature;
    }

    // boilWater方法,燒水
    public void boilWater(){
        for(int i = 30; i <= 100; i++){
            this.setTemperature(i);
            this.setChanged();
            this.notifyObservers(this.getTemperature());
            this.clearChanged();
        }
    }
}

2. java.util.Observer接口 = 觀察者

  Observer接口只有一個抽象方法須要被具體的觀察者實現。測試

public interface Observer{
    void update(Observable observable, Object arg); //這裏的arg即Obserbale類裏的notifyObservers(Object arg)傳過來的參數
}

  Note:當被觀察者調用nofityObservers(*)方法時,會根據被觀察者的hasChanged()方法來判斷它的狀態是否被改變。若是改變,則觀察者調用update方法。不然不調用(即不更新)。this

  顯示器和揚聲器做爲具體的熱水器水溫監視者,都須要實現Observer接口。對於顯示器,它的update方法做用就是更新顯示的水溫。對揚聲器,它的update方法則是在水溫超過90度時發出警告。具體代碼以下:spa

// 顯示器
public class Displayer implements Observer {
    public void update(Observable observable, Object arg){
        display((int)arg);
    }
  
    public void display(int temperature){
        System.out.println("Current Temperature is: " + temperature  + " degree.");
    }
}

// 揚聲器
public class Alertor implements Observer {
    public void update(Observable observable, Object arg){
        int temperature = (int) arg;
        if(temperature > 90){  
            alarm();
        }
    }

    public void alarm(){
        System.out.println("Warning: Temperature is over 90 degree!" );
    }
}

3. 測試類

public class TestObserver{
    public static void main(String[] args){
        // 生成設備
        Heater heater = new Heater();
        Displayer displayer = new Displayer();
        Alertor alertor = new Alertor();

        // 添加訂閱 - 重點(!!!)
        heater.addObserver(display);
        heater.addObserver(alertor);

        // 燒水
        heater.boilWater();
    }
}

4. 將上面的3個步驟統一塊兒來,寫到一個文件中以下:文件名TestObserver.java

import java.util.Observable;
import java.util.Observer;

public class TestObserver {
    public static void main(String[] args){
        // 生成設備
        Heater heater = new Heater();
        Displayer displayer = new Displayer();
        Alertor alertor = new Alertor();

        // 添加訂閱
        heater.addObserver(displayer);
        heater.addObserver(alertor);

        // 燒水
        heater.boilWater();
    }
}

class Heater extends Observable {
    private int temperature;

    // get方法,返回水溫
    public int getTemperature(){
        return temperature;
    }

    // set方法,設置水溫
    public void setTemperature(int temperature){
        this.temperature = temperature;
    }

    // boilWater方法,燒水
    public void boilWater(){
        for(int i = 30; i <= 100; i++){
            this.setTemperature(i);
            this.setChanged();
            this.notifyObservers(this.getTemperature());  // 只需傳入監視器感興趣的變量
            this.clearChanged();
        }
    }
}

// 顯示器
class Displayer implements Observer {
    public void update(Observable observable, Object arg){
        display((int)arg);
    }
  
    public void display(int temperature){
        System.out.println("Displayer: Current Temperature is: " + temperature  + " degree.");
    }
}

// 揚聲器
class Alertor implements Observer {
    public void update(Observable observable, Object arg){
        int temperature = (int) arg;
        if(temperature > 90){  
            alarm();
        }
    }

    public void alarm(){
        System.out.println("Alertor: Warning: Temperature is over 90 degree!" );
    }
}

最後的輸出結果爲:.net

Displayer: Current Temperature is:  30  degree.
Displayer: Current Temperature is:  31  degree.
Displayer: Current Temperature is:  32  degree.
...
Displayer: Current Temperature is:  90  degree.
Displayer: Current Temperature is:  91  degree.
Alertor: Warning: Temperature is over 90 degree!
Displayer: Current Temperature is:  92  degree.
Alertor: Warning: Temperature is over 90 degree!
...
Displayer: Current Temperature is:  99  degree.
Alertor: Warning: Temperature is over 90 degree!
Displayer: Current Temperature is:  100  degree.
Alertor: Warning: Temperature is over 90 degree!

總結

第一次寫技術博客感受比較費勁。原覺得一個下午能把三種實現方法都寫完的,結果只寫完了Java部分。後續的Objective-C 和C#部分計劃明天下午搞定。敬請期待。設計

歡迎交流和討論^_^ ~ 若有任何問題,請發送到郵箱:fengfu0527@gmail.com

 

[1]. 《Design Patterns: Elements of Reusable Object-Oriented Software》

[2]. Java之美之設計模式,連接:http://bolg.csdn.net/zhangerqing/article/details/8194653

[3]. 《Java與模式》

相關文章
相關標籤/搜索