一、概念 觀察者模式:定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,它的所有依賴者都會收到通知並自動更新。 觀察者模式四個角色: 1、抽象主題:定義對觀察者管理的介面,包括 訂閱、取消訂閱、通知介面。 2、具體主題:把所有觀察者對象的引用保存在一個聚集(比如Ar ...
一、概念
- 觀察者模式:定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,它的所有依賴者都會收到通知並自動更新。
觀察者模式四個角色:
1、抽象主題:定義對觀察者管理的介面,包括 訂閱、取消訂閱、通知介面。
2、具體主題:把所有觀察者對象的引用保存在一個聚集(比如ArrayList對象)里,實現抽象主題的介面,併在更新時通知觀察者。
3、抽象觀察者:為所有的具體觀察者定義一個介面,在得到主題通知時更新自己。
4、具體觀察者:實現抽象觀察者定義的介面,得到主題通知的數據(pull or push),並實現自己的邏輯。主題 + 觀察者 = 觀察者模式,可以用報紙訂閱服務來模擬這個模式 —— 報紙是主題,訂閱報紙的人是觀察者。觀察者可以選擇是否訂閱或者退訂主題。
二、Demo實現
1、主題
java.util 包中內置了一個抽象主題 Observable 類(有弊端,下文會提到),可以選擇繼承 Observable 類作為具體主題角色。
@AllArgsConstructor
@Getter
public class WeatherData extends Observable {
/**
* 溫度
*/
private Float temperature;
/**
* 濕度
*/
private Float humidity;
/**
* 壓力
*/
private Float pressure;
/**
* 假設改變的時候這個方法會被調用
*/
public void measurementsChanged() {
setChanged();
notifyObservers(); // 這種不帶參數的方式,由觀察者 pull 自己想要的數據。要什麼數據由觀察者自己決定。
//notifyObservers(Object arg) // 這種帶參數的方式,由主題 push 數據。傳什麼數據由主題決定。(推薦)
}
}
2、觀測者
java.util 包中內置了一個抽象觀察者 Observer 介面,可以選擇實現 Observer 介面的 update 方法作為具體觀察者角色,做更新的操作。
濕度觀察者:
public class HumidityObserver implements Observer {
public HumidityObserver(Observable observable) {
// 訂閱主題
observable.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
if (o instanceof WeatherData) {
WeatherData weatherData = (WeatherData) o;
Float humidity = weatherData.getHumidity();
System.out.println("我是一個濕度觀察者,我現在的濕度是:" + humidity);
}
}
}
壓力觀察者:
public class PressureObserver implements Observer {
public PressureObserver(Observable observable) {
// 訂閱主題
observable.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
if (o instanceof WeatherData) {
WeatherData weatherData = (WeatherData) o;
Float pressure = weatherData.getPressure();
System.out.println("我是一個壓力觀察者,我現在的壓力是:" + pressure);
}
}
}
溫度觀察者:
public class TemperatureObserver implements Observer {
public TemperatureObserver(Observable observable) {
// 訂閱主題
observable.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
if (o instanceof WeatherData) {
WeatherData weatherData = (WeatherData) o;
Float temperature = weatherData.getTemperature();
System.out.println("我是一個溫度觀察者,我現在的溫度是:" + temperature);
}
}
}
3、測試
public static void main(String[] args) {
// 具體主題實現
WeatherData weatherData = new WeatherData(24.0F,152F,100F);
// 觀察者訂閱
new HumidityObserver(weatherData);
new PressureObserver(weatherData);
new TemperatureObserver(weatherData);
// 事件發生
weatherData.measurementsChanged();
}
4、Observable 的弊端
- Observable 是一個“類”,而不是一個介面。所以你只能選擇繼承它,實現自己的具體主題,這大大限制了 Observable 的復用潛力,畢竟 Java 不支持多重繼承。
- Observable 的 setChanged 方法是 protected 屬性的,因此你除了選擇繼承 Observable 類,甚至無法使用組合來使用它。
- 如果有必要的話可以實現自己的 Observable 介面,不要害怕,這並不難。(鏈接代碼中有示例)
tips:"抽象"主題 和 具體主題標反了。汗~
演示源代碼:https://github.com/JMCuixy/design-patterns
三、總結
- 設計原則:觀察者模式是為了交互對象之間的松耦合設計而努力。
- 應用場景:一個對象狀態改變給其他對象通知的問題,而且要考慮到易用和低耦合,保證高度的協作。
- 優點:主題是真正擁有數據的人,觀察者是主題的依賴者,在數據變化時更新,這樣比起讓許多對象控制通一份數據類,可以得到更加乾凈的OO設計。
- 缺點:在應用觀察者模式時需要考慮一下開發效率和運行效率的問題,因為在Java中消息的通知一般是順序執行,那麼一個觀察者卡頓,會影響整體的執行效率,在這種情況下,我們一般會採用非同步實現。而且必須保證投遞是以自恰的方式進行的。