觀察者模式(Obserber Pattern):定義對象之間一對多的依賴,當一個對象改變狀態時,它的所有依賴者都會收到通知並自動更新。
觀察者模式主要用來處理一對多的數據更新和傳輸的關係。易於對實現對象的控制和更新。觀察者模式主要分爲兩部分,一部分稱爲主題(Subject)類似於報紙的出版商,另一部分稱爲觀察者(Observer)類似於報紙的訂購者。這個模式就相當於出版商和訂購者的關係,當訂購者需要得到數據時就會在出版商這裏註冊,以通知出版商,取得獲取數據的資格,一旦有數據更新的時候訂購者就像讀報紙一樣得到數據,這樣報社不需要去照顧訂購者的數量和實現方法。只需要對已註冊的跟新即可。
舉個例子
接到一個項目,用來做氣象監測,分爲兩個部分,一個是WeatherData對象:追蹤監測的氣象數據,並跟新佈告板。另一個是佈告板:通過終端(手機、電視、電腦)顯示當前天氣狀況給用戶。
分析需求:
已知:1)WeatherData類有三個get方法,取得三個測量值:溫度、溼度和氣壓。
2)有一個update方法。
3)一旦WeatherData有新的數據產生時,就會立即向佈告板更新。
4)需要可擴展,因爲終端不同,需要能讓其他開發人員建立佈告板。
這樣就可以來設計了,通過上面對觀察者的介紹和針對接口的OO原則。
定義主題接口:
//主題接口
public interface Subject{
//註冊觀察者方法
public void registerObserver(Observer ob);
//刪除觀察者方法
public void removeObserver(Observer ob);
//通知觀察者方法
public void notifyObserver(Observer ob);
}
觀察者接口:
//觀察者接口
public interface Observer{
//更新數據方法
public void update(float temp,float humidity,float pressure);
}
發佈接口:
//發佈接口
public interface DisplayElement{
public void display();
}
開始實現:
首先實現WeatherData
//通過Subject接口實現WeatherData
public class WeatherData implements Subject{
//定義一個列表,用來盛放註冊的觀察者
private ArrayList observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData(){
observers=new ArrayList();
}
public void registerObserver(Observer ob){
observers.add(ob);
}
public void removeObserver(Observer ob){
//返回此列表中首次出現的ob的索引,如果此列表不包含元素,則返回 -1。
if(observers.indexOf(ob)>=0)
observers.remove(ob);
}
public void notifyObserver(Observer ob){
for(int i=0;i<observers.size();i++){
Observer observer=(Observer) observers.get(i);
observer.update(temperature,humidity,pressure);
}
}
//當WeatherData數據改變時,纔會更新。
public void measurementsChanged(){
notifyObserver();
}
public void setMeasurements(float temperature,float humidity,float pressure){
this.temperature=temperature;
this.humidity=humidity;
this.pressure=pressure;
measurementsChanged();
}
}
}
通過Observer實現佈告板:
//通過Observer接口實佈告板
public class BillBoard implements Observer,DisplayElement(){
private float temperature;
private float humidity;
private float pressure;
public BillBoard(Subject WeatherData){
this.WeatherData=WeatherData;
WeatherData.removeObserver(this);
}
public void update(float temperature,float humidity,float pressure){
this.temperature=temperature;
this.humidity=humidity;
this.pressure=pressure;
display();
}
/*
這個方法由開發人員重寫
*/
@Override
public void display(){
}
}
這樣整個設計基本上就OK了,下面寫個test類來測試一下:
//測試類
public class test{
public static void main(String args[]){
WeatherData watherData=new WeatherData();
BillBoard billBoard=new BillBoard();
//不止這一個公告板,如果有的話在下面繼續加
weatherData.setMeasurements(22,55,66);
weatherData.setMeasurements(5,96,47);
}
}
不出錯的話這個任務基本上就完成了。
到目前爲止,已經從無到有的完成了Observer Pattern。關於觀察者,主題只知道觀察者實現的Observer接口,不需要知道其他的任何細節。 任何時候都可以增加新的觀察者,只需要在主題ArrayList裏面註冊就可以。 有新的類型觀察者出現時,主題代碼還是不需要修改,主題代碼不在乎別的,只有一個功能就是給已註冊的觀察者發送數據。 獨立的複用主題或者觀察者,二者獨立,只需要遵守接口,改變不會產生影響。
多說一點,上面的這種設計實際上是由主題進行一個類似於“推”的動作,它把數據推送到各個觀察者。觀察者是被動接收數據的對象。實際上Java有一個內置的觀察者模式,實現的是另一種不同的思路。說白了是“拉”,觀察者從主題裏去拉取自己需要的數據,去按照自己的需求主動獲取數據。位於java.util包裏。