觀察者模式(Observer Pattern)
觀察者模式(Observer Pattern)是一種行為設(shè)計(jì)模式,它定義了對象之間的一對多依賴關(guān)系,當(dāng)一個(gè)對象的狀態(tài)發(fā)生改變時(shí),所有依賴它的對象都會(huì)得到通知并自動(dòng)更新。這種模式也被稱作發(fā)布 - 訂閱(Publish - Subscribe)模式。下面從多個(gè)方面詳細(xì)介紹觀察者模式。
模式結(jié)構(gòu)與角色
觀察者模式主要包含以下幾個(gè)角色:
- 主題(Subject):也稱為被觀察者,它維護(hù)一個(gè)觀察者列表,提供注冊、移除觀察者的方法,并且在自身狀態(tài)改變時(shí)通知所有注冊的觀察者。
- 具體主題(Concrete Subject):實(shí)現(xiàn)主題接口,當(dāng)狀態(tài)發(fā)生變化時(shí),調(diào)用通知方法來通知所有觀察者。
- 觀察者(Observer):定義了一個(gè)更新方法,當(dāng)主題狀態(tài)改變時(shí),該方法會(huì)被調(diào)用以進(jìn)行相應(yīng)的更新操作。
- 具體觀察者(Concrete Observer):實(shí)現(xiàn)觀察者接口,在接收到主題的通知后,執(zhí)行具體的更新邏輯。
代碼示例
以下是一個(gè)簡單的 Java 代碼示例,模擬一個(gè)天氣站(主題)和多個(gè)顯示器(觀察者)的場景:
import java.util.ArrayList;
import java.util.List;
// 觀察者接口
interface Observer {
void update(float temperature, float humidity, float pressure);
}
// 主題接口
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具體主題:天氣站
class WeatherStation implements Subject {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherStation() {
observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
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();
}
}
// 具體觀察者:當(dāng)前天氣顯示器
class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
private Subject weatherStation;
public CurrentConditionsDisplay(Subject weatherStation) {
this.weatherStation = weatherStation;
weatherStation.registerObserver(this);
}
@Override
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");
}
}
// 客戶端代碼
public class ObserverPatternExample {
public static void main(String[] args) {
WeatherStation weatherStation = new WeatherStation();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherStation);
weatherStation.setMeasurements(80, 65, 30.4f);
weatherStation.setMeasurements(82, 70, 29.2f);
weatherStation.setMeasurements(78, 90, 29.2f);
}
}
代碼解釋
- 觀察者接口
Observer
:定義了update
方法,當(dāng)主題狀態(tài)改變時(shí),觀察者通過該方法接收更新信息。 - 主題接口
Subject
:包含registerObserver
用于注冊觀察者,removeObserver
用于移除觀察者,notifyObservers
用于通知所有注冊的觀察者。 - 具體主題
WeatherStation
:實(shí)現(xiàn)了Subject
接口,維護(hù)一個(gè)觀察者列表,當(dāng)天氣測量數(shù)據(jù)發(fā)生變化時(shí),調(diào)用notifyObservers
方法通知所有觀察者。 - 具體觀察者
CurrentConditionsDisplay
:實(shí)現(xiàn)了Observer
接口,在update
方法中更新顯示的天氣信息,并調(diào)用display
方法顯示當(dāng)前天氣狀況。 - 客戶端代碼:創(chuàng)建了天氣站和顯示器對象,天氣站更新測量數(shù)據(jù),顯示器接收到通知并顯示最新的天氣信息。
優(yōu)點(diǎn)
- 松耦合:主題和觀察者之間是松耦合的關(guān)系,主題只需要知道觀察者實(shí)現(xiàn)了
Observer
接口,而不需要了解具體的觀察者類。這使得主題和觀察者可以獨(dú)立變化,提高了系統(tǒng)的可維護(hù)性和可擴(kuò)展性。 - 支持廣播通信:主題可以同時(shí)通知多個(gè)觀察者,實(shí)現(xiàn)了一對多的通信機(jī)制。
- 符合開閉原則:可以方便地添加或移除觀察者,而不需要修改主題的代碼。
缺點(diǎn)
- 觀察者過多時(shí)性能問題:如果觀察者數(shù)量過多,通知所有觀察者可能會(huì)導(dǎo)致性能下降。
- 循環(huán)依賴問題:如果主題和觀察者之間存在循環(huán)依賴,可能會(huì)導(dǎo)致系統(tǒng)出現(xiàn)問題,需要小心處理。
應(yīng)用場景
- 事件處理系統(tǒng):例如,圖形用戶界面(GUI)中的按鈕點(diǎn)擊事件,當(dāng)按鈕被點(diǎn)擊(主題狀態(tài)改變)時(shí),會(huì)通知所有注冊的事件監(jiān)聽器(觀察者)進(jìn)行相應(yīng)的處理。
- 消息通知系統(tǒng):如社交網(wǎng)絡(luò)中的消息推送,當(dāng)用戶發(fā)布新消息(主題狀態(tài)改變)時(shí),會(huì)通知所有關(guān)注該用戶的其他用戶(觀察者)。
- 股票價(jià)格監(jiān)控系統(tǒng):股票價(jià)格(主題)發(fā)生變化時(shí),會(huì)通知所有關(guān)注該股票的投資者(觀察者)。
Java設(shè)計(jì)模式 文章被收錄于專欄
設(shè)計(jì)模式是軟件開發(fā)中針對反復(fù)出現(xiàn)的問題所總結(jié)歸納出的通用解決方案,它可以幫助開發(fā)者更高效地構(gòu)建軟件系統(tǒng),提升代碼的可維護(hù)性、可擴(kuò)展性和可復(fù)用性。