實例
該實例模擬了燒水的過程,涉及三個對象,Heater(熱水器),Display(顯示器),Alarm(報警器).
模擬過程:為了便於運行,水的初始化溫度為90,沸點為95,顯示器依據熱水器顯示溫度,顯示器顯示溫度為95時,報警器開始報警。明顯可以看出Heater是subject ,Display 是它的 Observer,同時Display亦是subject,因為它要被報警器觀察,所以Alarm是Display的Observer.
實現過程:
a.Heater.java
Java代碼
import java.util.Observable;
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 < 100; i++) {
temperature = i;
this.setChanged();
this.notifyObservers();
}
}
}
b.Display.java
Java代碼
import java.util.Observable;
import java.util.Observer;
public class Display extends Observable implements Observer {
private String status = "未開";
public void setStatus(String status) {
this.status = status;
}
public void displayTemputer(int temperature) {
if (temperature > 95) {
this.setStatus("沸騰");
this.setChanged();
this.notifyObservers();
}
System.out.println("狀態:" + status + " 現在溫度:" + temperature + "");
}
public void update(Observable o, Object arg) {
displayTemputer(((Heater) o).getTemperature());//這裡不是很好
}
}
c.Alarm.java
Java代碼
import java.util.Observable;
import java.util.Observer;
public class Alarm implements Observer {
public void makeAlarm() {
System.out.println("嘀嘀嘀...水已經燒開 ");
}
public void update(Observable o, Object arg) {
makeAlarm();
}
}
d.測試類testObserver.java
Java代碼
public class testObserver {
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();
}
}
e.運行結果:
引用
狀態:未開 現在溫度:90
狀態:未開 現在溫度:91
狀態:未開 現在溫度:92
狀態:未開 現在溫度:93
狀態:未開 現在溫度:94
狀態:未開 現在溫度:95
嘀嘀嘀...水已經燒開
狀態:沸騰 現在溫度:96
嘀嘀嘀...水已經燒開
狀態:沸騰 現在溫度:97
嘀嘀嘀...水已經燒開
狀態:沸騰 現在溫度:98
嘀嘀嘀...水已經燒開
狀態:沸騰 現在溫度:99
套用
1、 對一個對象狀態的更新,需要其他對象同步更新,而且其他對象的數量動態可變。
2、 對象僅需要將自己的更新通知給其他對象而不需要知道其他對象的細節。
優缺點
觀察者模式的優點:
1、 Subject和Observer之間是松耦合的,分別可以各自獨立改變。
2、 Subject在傳送廣播通知的時候,無須指定具體的Observer,Observer可以自己決定是否要訂閱Subject的通知。
3、 遵守大部分GRASP原則和常用設計原則,高內聚、低耦合。
觀察者模式的缺陷:
1、 松耦合導致代碼關係不明顯,有時可能難以理解。(廢話)
2、 如果一個Subject被大量Observer訂閱的話,在廣播通知的時候可能會有效率問題。(畢竟只是簡單的遍歷)
補充說明:
1.如何應對缺陷2?
缺陷2這個問題由兩個部分組成。
其中之一是由於使用了推模型(push model)而不是拉模型(pull model),導致所有Observer都被通知了大量的數據。利用拉模型可以檢查是否是自己感興趣的通知,從而由各個Observer有選擇的詢問數據。
其二是在複雜的Observer模式套用場景中,由於存在複數個Subject對應單個Observer或者單個Subject對應複數個Observer。單純的對每個Subject的所有Observer依次更新會產生冗餘的更新。可以通過引入更改管理器(changeManager)這箇中介來解決。 利用Mediator模式我們可以引入更改管理器來管理Subject與Observer之間的依賴關係,得到依賴關係的有向無環圖DAG,利用這個圖來遍歷更新就可以避免前述的重複更新問題。
(參考《設計模式:可復用面向對象軟體的基礎》)