java 觀察者模式

java觀察者模式介紹

概念html

 Observer模式定義對象間的一對多的依賴關係,當一個對象(被觀察者)的狀態發生改變時, 全部依賴於它的對象(觀察者)都獲得通知並被自動更新。JDK裏提供的observer設計模式的實現由java.util.Observable類和 java.util.Observer接口組成。從名字上能夠清楚的看出二者在Observer 設計模式中分別扮演的角色:Observer是觀察者角色,Observable是被觀察目標(subject)角色。java

相關類介紹web

1.Obervable設計模式

此類表示模型視圖範例中的 observable 對象,繼承它的類表示應用程序想要觀察的對象。一個 observable 對象能夠有一個或多個觀察者。觀察者是實現Observer接口的任意對象。一個 observable 實例改變後,調用 Observable 的 notifyObservers 方法的應用程序會經過調用觀察者的 update 方法來通知觀察者該實例發生了改變。安全

方法摘要框架

 voidide

addObserver(Observer o) 
          若是觀察者與集合中已有的觀察者不一樣,則向對象的觀察者集中添加此觀察者。未指定向多個觀察者發送通知的順序。post

protected  void性能

clearChanged() 
          指示對象再也不改變,或者它已對其全部的觀察者通知了最近的改變,因此 hasChanged 方法將返回 false。notifyObservers 方法自動調用此方法。測試

 int

countObservers() 
          返回 Observable 對象的觀察者數目。

 void

deleteObserver(Observer o) 
          從對象的觀察者集合中刪除某個觀察者。向此方法傳遞 null無效。

 void

deleteObservers() 
          清除觀察者列表,使此對象再也不有任何觀察者。

 boolean

hasChanged() 
          測試對象是否改變。當且僅當在此對象上最近調用了 setChanged 方法時才返回 true;不然返回 false。

 void

notifyObservers() 
          若是 hasChanged 方法指示對象已改變,則通知其全部觀察者,並調用 clearChanged 方法來指示此對象再也不改變。

每一個觀察者都有其 update 方法,其調用參數有兩個:observable 對象和 null。換句話說,此方法等效於: notifyObservers(null)

 void

notifyObservers(Object arg) 
          若是 hasChanged 方法指示對象已改變,則通知其全部觀察者,並調用 clearChanged 方法來指示此對象再也不改變。

每一個觀察者都有其 update 方法,其調用參數有兩個:observable 對象和 arg 參數。 arg 能夠是任意對象

protected  void

setChanged() 
          標記此 Observable 對象爲已改變的對象;如今 hasChanged 方法將返回 true

 

關於發送通知的順序

Observable 類中所提供的默認實現將按照其註冊的重要性順序來通知 Observers,可是子類可能改變此順序,從而使用非固定順序在單獨的線程上發送通知,或者也可能保證其子類聽從其所選擇的順序。

注意:此通知機制與線程無關,而且與 Object 類的 wait  notify 機制徹底獨立。

新建立一個 observable 對象時,其觀察者集是空的。當且僅當 equals 方法爲兩個觀察者返回 true 時,才認爲它們是相同的。

 

2.Oberver接口

這是個接口類,這個接口只有一個爲實現的抽象方法update。實現該接口的對象成爲觀察者,該對象要實現update方法。註冊了該對象(觀察者)的對象(觀察者)實例條用notifiyObservers方法後,觀察者會自動執行update方法。

方法摘要

 void

update(Observable o, Object arg) 
          只要改變了 observable 對象就調用此方法。

o - observable 對象。

arg - notifyObservers 方法的參數。

 

實例

該實例模擬了燒水的過程,涉及三個對象,Heater(熱水器),Display(顯示器),Alarm(報警器).

模擬過程:爲了便於運行,水的初始化溫度爲90,沸點爲95,顯示器依據熱水器顯示溫度,顯示器顯示溫度爲95時,報警器開始報警。明顯能夠看出Heater是subject ,Display 是它的 Obsrver,同時Display亦是subject,由於它要被報警器觀察,因此Alarm是Display的Observer.

 

Heater.java

public class Heater extends Observable {

    private int temperature;

 

    public int getTemperature() {

       return temperature;

    }

 

    public void setTemperature(int temperature) {

       this.temperature = temperature;

    }

 

    public void boilWater() {

       for (int i = 90; i < 110; i++) {

           temperature = i;

       this.setChanged();

       this.notifyObservers();

       }

    }

}

 

Display.java

public class Display extends Observable implements Observer {

    private String status = "未開";

 

    public String getStatus() {

       return status;

    }

 

    public void setStatus(String status) {

       this.status = status;

    }

 

    @Override

    public void update(Observable o, Object arg) {

       this.displayTemperature(((Heater) o).getTemperature());

    }

 

    private void displayTemperature(int temperature) {

       if (temperature > 100) {

           this.setStatus("沸騰");

           this.setChanged();

           this.notifyObservers(temperature);

       }

       System.out.println("狀態: " + status + "  如今溫度: " + temperature);

    }

}

 

Alarm.java

public class Alarm implements Observer {

    @Override

    public void update(Observable arg0, Object arg1) {

       this.makeAlarm((Integer) arg1);

    }

 

    private void makeAlarm(int temperature) {

       System.out.println("嘀嘀嘀。。。水已經燒開了");

       // System.out.println("如今水溫是: " + temperature);

    }

}

 

TestMain.java測試入口類

public class TestMain {

    public static void main(String[] args) {

       Heater heater = new Heater();

       Display display = new Display();

       Alarm alarm = new Alarm();

       heater.addObserver(display);

       display.addObserver(alarm);

       heater.boilWater();

    }

}

優勢

  • 支持鬆耦合和減小依賴性。客戶端再也不依賴於觀察器,由於經過使用主體和 Observer 接口對客戶端進行了隔離。許多框架具備此優勢,在這些框架中的應用程序組件能夠註冊爲當(低級)框架事件發生時獲得通知。結果,框架將調用應用程序組件,但不會依賴於它。
  • 觀察器數目可變。觀察器能夠在運行時附加和分離,由於主體對於觀察器數目沒有任何假定。此功能在這樣的狀況下是頗有用的:觀察器數在設計時是未知的。例如,若是用戶在應用程序中打開的每一個窗口都須要一個觀察器。

缺點

  • 性能下降。在許多實現中,觀察器的 update() 方法可能與主體在同一線程中執行。若是觀察器列表很長,則執行 Notify() 方法可能須要很長時間。抽取對象依賴性並不意味着添加觀察器對應用程序沒有任何影響。
  • 內存泄漏。在 Observer 中使用的回調機制(當對象註冊爲之後調用時)會產生一個常見的錯誤,從而致使內存泄漏,甚至是在託管的 C# 代碼中。假定觀察器超出做用範圍,但忘記取消對主體的訂閱,那麼主體仍然保留對觀察器的引用。此引用防止垃圾收集在主體對象也被破壞以前從新分配與觀察器關聯的內存。若是觀察器的生存期比主體的生存期短得多(一般是這種狀況),則會致使嚴重的內存泄漏。
  • 隱藏的依賴項。觀察器的使用將顯式依賴性(經過方法調用)轉變爲隱式依賴性(經過觀察器)。若是在整個應用程序中普遍地使用觀察器,則開發人員幾乎不可能經過查看源代碼來了解所發生的事情。這樣,就使得了解代碼更改的含意很是困難。此問題隨傳播級別急劇增大(例如,充當 Subject 的觀察器)。所以,應該僅在少數定義良好的交互(如 Model-View-Controller 模式中模型和視圖之間的交互)中使用觀察器。最好不要在域對象之間使用觀察器。
  • 測試 / 調試困難。儘管鬆耦合是一項重大的體系結構功能,可是它可使開發更困難。將兩個對象去耦的狀況越多,在查看源代碼或類的關係圖時瞭解它們之間的依賴性就越難所以,僅當能夠安全地忽略兩個對象之間的關聯時才應該將它們鬆耦合(例如,若是觀察器沒有反作用)。

參考文章:

http://baike.baidu.com/view/6547055.htm

http://msdn.microsoft.com/zh-cn/library/ms978753.aspx

相關文章
相關標籤/搜索