觀察者模式:
定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,它的全部依賴者都會收到通知並自動更新。
設計原則:
爲了交互對象之間的鬆耦合設計而努力。
主題和觀察者定義了一對多的關係,參見報紙訂閱服務,報社是主題,用戶是觀察者們。
出版方+訂閱者=觀察者模式:
一、當報社出版新的報紙時,會推送給用戶。只要是報社的訂戶,就會一直收到新報紙。
二、取消報紙訂閱服務,就不會收到新報紙。
三、只要報社還在運營,就會一直有人向報社訂閱報紙或取消訂閱。
主題向觀察者推送消息,有兩種推送消息的方式,「推」和「拉」。
實例:創建一個氣象觀測站,WeatherData對象知道如何從氣象站獲取最新數據,隨即顯示在佈告板上。
如下是「推」的方式:主題推送數據給觀察者。
Java由內置的觀察者模式API,但如下用自定義的觀察者模式來實現「推」方式:
package mypackage;
public interface Subject { //主題接口
public void registerObserver(Observer o);//註冊觀察者
public void removeObserver(Observer o);//移除觀察者
public void notifyObservers(); //通知更新
}
package mypackage;
public interface Observer { //觀察者接口
public void update(float temp,float humidity,float pressure);
}
package mypackage;
public interface DisplayElement { //佈告板接口
public void display();
}
package mypackage;
import java.util.ArrayList;
public class WeatherData implements Subject { //具體的主題 WeatherData
private ArrayList observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers=new ArrayList();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if(i>0) {
observers.remove(i);
}
}
@Override
public void notifyObservers() {
for(int i = 0;i<observers.size();i++) {
Observer observer=(Observer)observers.get(i);
observer.update(temperature, humidity, pressure);
}
}
public void measurementsChanged() {
notifyObservers();
}
public void setMeasurements(float temperature,float humidity,float pressure) {//獲取氣象數據,這些數據由咱們手動賦值
this.temperature=temperature;
this.humidity=humidity;
this.pressure=pressure;
measurementsChanged();
}
}
package mypackage;
public class CurrentConditionDisplay implements Observer, DisplayElement {//具體的觀察者,一個對象就是一個觀察者
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionDisplay(Subject weatherData) {
this.weatherData=weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("Current conditions:"+temperature+"F degrees and"+humidity+"%humidity");
}
@Override
public void update(float temperature, float humidity, float pressure) {//獲取更新數據
this.temperature=temperature;
this.humidity=humidity;
display();
}
}
package mypackage;
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionDisplay currentDisplay=new CurrentConditionDisplay(weatherData);//建立一個觀察者實例
weatherData.setMeasurements(80, 65, 30.4f);//賦值氣象數據
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}
如下是「拉」的方式:
利用Java內置API實現:
package mypackage;
public interface DisplayElement { //自定義的佈告板接口
public void display();
}
package mypackage;
import java.util.Observable;//Java內置的主題類
public class WeatherData extends Observable{
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {}
public void measurementsChangerd() {
setChanged(); //須要,把changed標誌設置爲true,notifyObservers()纔會通知觀察者
notifyObservers();
}
public void setMeasurements(float temperature,float humidity,float pressure) {
this.temperature=temperature;
this.humidity=humidity;
this.pressure=pressure;
measurementsChangerd();
}
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
public float getPressure() {
return pressure;
}
}
package mypackage;
import java.util.Observable;
import java.util.Observer; //Java內置的觀察者接口
public class CurrentConditionsDisplay implements Observer, DisplayElement{
Observable observable;
private float temperature;
private float humidity;
public CurrentConditionsDisplay(Observable observable) {
this.observable=observable;
observable.addObserver(this);
}
@Override
public void display() {
System.out.println("Current conditions:"+temperature+"F degrees and"+humidity+"%humidity");
}
@Override
public void update(Observable o, Object arg) {
if(o instanceof WeatherData) {
WeatherData weatherData = (WeatherData)o;
this.temperature=weatherData.getTemperature(); //「拉」數據
this.humidity=weatherData.getHumidity();
display();
}
}
}
package mypackage;
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay=new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}
Java內置的Observable是一個類,類是單繼承的,限制了複用潛力。沒有Observable接口也沒法創建本身的實現 和Java內置的ObserverAPI搭配使用也沒法換成另外一套實現,好比setChanged()是受保護的,除非繼承, 不然沒法建立Observable實例並組合到本身的對象中。