設計模式之觀察者模式(Observer Pattern)
觀察者模式
觀察者模式定義了物件之間的一對多依賴,這樣一來,當一個物件改變狀態時,它的所有依賴者都會收到通知並自動更新
在觀察者模式中,發生改變的物件稱為觀察目標,而被通知的物件稱為觀察者,一個觀察目標可以對應多個觀察者。一個軟體系統常常要求在某一個物件的狀態發生變化的時候,依賴它的物件作出相應的改變。如JDK中java.util的觀察者模式、JavaBean和Swing。為了使系統易於複用,應該選擇低耦合的設計方案。減少物件之間的耦合度有利於系統的複用,但同時設計師需要使這些低耦合度的物件之間能夠維持行動的協調一致,保證高度的協作。觀察者模式是滿足這一要求的各種設計方案中最重要的一種。
觀察者模式是物件的行為模式,又叫釋出-訂閱(Publish/Subscribe)模式、模型-檢視(Model/View)模式、源-監聽器(Source/Listener)模式或從屬者(Dependents)模式。
###觀察者模式結構重要核心模組
抽象主題(Subject)
抽象主題角色把所有對觀察者的引用儲存在一個聚集裡(如ArrayList物件裡),每個主題都可以有任何數量的觀察者。抽象主題提供addObserver()和deleteObserver()介面,可以增加和刪除觀察者物件,抽象主題角色又叫做抽象被觀察者(Observable)角色
具體主題(ConcreteSubject)
將有關狀態存入具體觀察者物件,在具體主題內部狀態改變時,給所有註冊過的觀察者發出通知。具體主題角色又叫做具體被觀察者(Concrete Observable)角色
抽象觀察者(Observer)
為所有的具體觀察者定義一個介面,在得到主題的通知時更新自己,這個介面叫做更新介面。
具體觀察者(ConcreteObserver)
儲存與主題的狀態自恰的狀態。具體觀察者角色實現抽象觀察者角色所要求的更新介面,以便使本身的狀態與主題的狀態 像協調。如果需要,具體觀察者角色可以保持一個指向具體主題物件的引用。
使用場景
一個物件的改變將導致一個或多個其他物件也發生改變,而並不知道具體有多少物件將發生改變,也不知道這些物件是誰。
需要在系統中建立一個觸發鏈,A物件的行為將影響B物件,B物件的行為將影響C物件……,可以使用觀察者模式建立一種鏈式觸發機制。
定義觀察者模式
例項
Subject
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
Observer
public interface Observer {
public void update(float temp, float humidity, float pressure);
}
DisplayElement
public interface DisplayElement {
public void display();
}
WeatherDate
import java.util.*;
public class WeatherData implements Subject {
private ArrayList<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<Observer>();
}
public void registerObserver(Observer o) {
observers.add(o);
}
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if (i >= 0) {
observers.remove(i);
}
}
public void notifyObservers() {
for (Observer observer : observers) {
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();
}
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
public float getPressure() {
return pressure;
}
}
CurrentConditionsDisplay
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("Current conditions: " + temperature
+ "F degrees and " + humidity + "% humidity");
}
}
WeatherStation
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay =
new CurrentConditionsDisplay(weatherData);
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}