觀察者模式 定義了對象之間的一對多依賴,這樣一來,當一個對象狀態改變時,它的所有依賴者都會收到通知並自動更新。 觀察者模式中,分為推和拉兩種模式。 推模式,即主題對象向觀察者對象推送狀態值,不管觀察者對象是否需要,並且推送全部數據或者部分數據。 拉模式,即主題對象通知觀察者對象狀態值已改變,觀察者根 ...
觀察者模式 定義了對象之間的一對多依賴,這樣一來,當一個對象狀態改變時,它的所有依賴者都會收到通知並自動更新。 觀察者模式中,分為推和拉兩種模式。 推模式,即主題對象向觀察者對象推送狀態值,不管觀察者對象是否需要,並且推送全部數據或者部分數據。 拉模式,即主題對象通知觀察者對象狀態值已改變,觀察者根據自己需要決定是否主動到主體對象中獲取詳細信息。 兩種模式的比較
1、推模型是假定主題對象知道觀察者需要的數據;而拉模型是主題對象不知道觀察者具體需要什麼數據,沒有辦法的情況下,乾脆把自身傳遞給觀察者,讓觀察者自己去按需要取值。
2、推模型可能會使得觀察者對象難以復用,因為觀察者的update()方法是按需要定義的參數,可能無法兼顧沒有考慮到的使用情況。這就意味著出現新情況的時候,就可能提供新的update()方法,或者是乾脆重新實現觀察者;而拉模型就不會造成這樣的情況,因為拉模型下,update()方法的參數是主題對象本身,這基本上是主題對象能傳遞的最大數據集合了,基本上可以適應各種情況的需要。
說明: 1、觀察者模式將觀察者和主題(被觀察者)的對象分離開,實現了兩者的松耦合。提高了應用程式的可維護性和重用性; 2、JAVA API 內置有觀察者模式。位於java.util包,包含有最基本的Observer介面與Observable類,分別對應觀察者和主題; 3、主題僅需要把實時的狀態值更新給觀察者即可,而不需要知道觀察者怎樣處理數據或者其他細節。 場景: 1、對於一個對象的狀態值需要實時更新到其他任何幾個對象。如氣象站檢測的天氣數據,要實時更新給氣象網站的佈告板。/** * 主題類介面。 * 用來定義註冊觀察者、移除觀察者、通知更新等方法 * @author xiabaike */ public interface Subject { /** * 註冊觀察者 * */ public void registerObserver(Observer o); /** * 移除觀察者 * */ public void removeObserver(Observer o); /** * 當狀態改變時,調用此方法,通知所有觀察者 * */ public void notifyObservers(); } |
/** * 觀察者類介面。 * 當主題狀態發生改變時,主題會把這些狀態值當做方法的參數,傳送給觀察者。 * @author xiabaike * */ public interface Observer { /** * 當主題狀態發生改變時,主題會把這些狀態值當做方法的參數,傳送給觀察者 * 所有觀察者都必須實現此方法,以實現觀察者介面 * */ public void update(float temp, float humidity, float pressure); } |
/** * 展示。在佈告板上顯示內容 * */ public interface DisplayElement { /** * 當佈告板需要顯示時,調用此方法 * */ public void display(); } |
/** * 天氣數據類。產生更新狀態值,並通知佈告板觀察者 * */ public class WeatherData implements Subject{ // 用來存放所有的觀察者 private List<Observer> observerList; private float tempPerature; private float humidity; private float pressure; public WeatherData() { observerList = new ArrayList<Observer>(); } public void registerObserver(Observer o) { observerList.add(o); } public void removeObserver(Observer o) { if(observerList.contains(o)) { observerList.remove(o); } } public void notifyObservers() { for(int i = 0; i < observerList.size(); i++) { observerList.get(i).update(tempPerature, humidity, pressure); } } /** * 當從氣象站得到更新觀測值時,通知觀察者 * */ public void setMeasurements(float temperature, float humidity, float pressure) { this.tempPerature = temperature; this.humidity = humidity; this.pressure = pressure; notifyObservers(); } } |
/** * 具體佈告板實現類。獲取狀態值,並展示 * */ public class CurrentConditionsDisplay implements Observer, DisplayElement{ private float tempPerature; private float humidity; private float pressure; private Subject subject; public CurrentConditionsDisplay(Subject subject) { this.subject = subject; this.subject.registerObserver(this); } public void update(float temp, float humidity, float pressure) { this.tempPerature = temp; this.humidity = humidity; this.pressure = pressure; display(); } public void display() { System.out.println("Current conditions: " + tempPerature +", "+ humidity +", "+ pressure); } } |
/** * 主類,模擬氣象站產生檢測數據,並更新給佈告板 * */ public class WeatherStation { public static void main(String[] args) { WeatherData subject = new WeatherData(); CurrentConditionsDisplay observer = new CurrentConditionsDisplay(subject); subject.setMeasurements(1, 2, 3); } } |