掌握設(shè)計(jì)模式--觀察者模式
觀察者模式(Observer Pattern)
觀察者模式(Observer Pattern)是一種行為設(shè)計(jì)模式,它定義了對(duì)象間的一對(duì)多依賴關(guān)系,使得當(dāng)一個(gè)對(duì)象狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都會(huì)自動(dòng)收到通知并更新。
主要組成部分
主題(Subject):主題是被觀察的對(duì)象,它維護(hù)一個(gè)觀察者列表。當(dāng)它的狀態(tài)發(fā)生改變時(shí),會(huì)通知所有的觀察者。主題提供方法來(lái)注冊(cè)、注銷觀察者。
觀察者(Observer):觀察者是依賴于主題的對(duì)象,它會(huì)在主題狀態(tài)發(fā)生變化時(shí)收到通知,進(jìn)而更新自身的狀態(tài)。觀察者有一個(gè)更新方法,當(dāng)主題狀態(tài)變化時(shí),主題會(huì)調(diào)用此方法來(lái)通知觀察者。
工作流程
- 注冊(cè)觀察者:觀察者通過(guò)主題提供的注冊(cè)方法將自己注冊(cè)到主題上。
- 狀態(tài)變化:主題的狀態(tài)發(fā)生變化時(shí),它會(huì)遍歷其所有注冊(cè)的觀察者。
- 通知觀察者:主題調(diào)用每個(gè)觀察者的更新方法,通知它們進(jìn)行狀態(tài)更新。
- 更新觀察者:觀察者根據(jù)通知更新自己的狀態(tài),通常會(huì)重新渲染界面或進(jìn)行其他的狀態(tài)更新。
案例實(shí)現(xiàn)
假設(shè)有一個(gè)溫度監(jiān)控系統(tǒng):
- 主題:溫度傳感器,當(dāng)溫度發(fā)生變化時(shí),它會(huì)通知所有依賴于它的觀察者。
- 觀察者:可以是不同的顯示設(shè)備或報(bào)警系統(tǒng),溫度變化時(shí),它們會(huì)根據(jù)新溫度執(zhí)行相應(yīng)操作。
案例類圖

觀察者接口
用于觀察溫度變化的接口,訂閱的主題發(fā)生變化時(shí),通過(guò)觀察者接口的update方法來(lái)通知訂閱了的所有觀察者。
interface Observer {
void update(int temperature);
}
觀察者實(shí)現(xiàn)類
// 觀察者實(shí)現(xiàn)類1
class DisplayDevice implements Observer {
@Override
public void update(int temperature) {
System.out.println("顯示裝置:溫度更新到" + temperature);
}
}
// 觀察者實(shí)現(xiàn)類2
class AlarmSystem implements Observer {
@Override
public void update(int temperature) {
if (temperature > 42) {
System.out.println("警報(bào):溫度超過(guò)閾值!");
}
}
}
主題類(被觀察者)
class TemperatureSensor {
// 觀察者列表
private List<Observer> observers = new ArrayList<>();
private int temperature;
// 注冊(cè)觀察者
public void addObserver(Observer observer) {
observers.add(observer);
}
// 移除觀察者
public void removeObserver(Observer observer) {
observers.remove(observer);
}
// 設(shè)置溫度并通知觀察者
public void setTemperature(int temperature) {
this.temperature = temperature;
notifyObservers();
}
// 通知所有觀察者
private void notifyObservers() {
for (Observer observer : observers) {
observer.update(temperature);
}
}
}
測(cè)試客戶端
public class ObserverPatternDemo {
public static void main(String[] args) {
// 創(chuàng)建主題和觀察者
TemperatureSensor sensor = new TemperatureSensor();
Observer display = new DisplayDevice();
Observer alarm = new AlarmSystem();
// 注冊(cè)觀察者:如果沒注冊(cè),那就不會(huì)通知
sensor.addObserver(display);
sensor.addObserver(alarm);
// 改變主題的狀態(tài)
sensor.setTemperature(45);
sensor.setTemperature(28);
}
}
測(cè)試輸出結(jié)果
顯示裝置:溫度更新到45
警報(bào):溫度超過(guò)閾值!
顯示裝置:溫度更新到28
優(yōu)缺點(diǎn)和使用場(chǎng)景
優(yōu)點(diǎn)
- 松耦合:觀察者與主題之間是松耦合的,主題不需要知道具體的觀察者,觀察者也不需要了解主題的內(nèi)部實(shí)現(xiàn)。
- 動(dòng)態(tài)添加或刪除觀察者:可以在運(yùn)行時(shí)動(dòng)態(tài)地添加或刪除觀察者。
缺點(diǎn)
- 多次更新:如果有大量觀察者,狀態(tài)變化可能導(dǎo)致多次調(diào)用更新方法,性能可能受到影響。
- 循環(huán)依賴:觀察者之間如果互相通知更新,可能引起循環(huán)依賴或無(wú)限循環(huán)。
觀察者模式是處理事件驅(qū)動(dòng)系統(tǒng)或需要多個(gè)對(duì)象同步更新狀態(tài)的常用模式,尤其在分布式系統(tǒng)、GUI框架中應(yīng)用廣泛。
適用場(chǎng)景
- 事件驅(qū)動(dòng)的系統(tǒng):例如GUI框架(按鈕點(diǎn)擊、界面更新等)、消息通知系統(tǒng)等。
- 發(fā)布-訂閱系統(tǒng):如消息隊(duì)列系統(tǒng)、新聞?dòng)嗛啞⑸缃幻襟w更新等。
- 數(shù)據(jù)同步:多個(gè)模塊需要同步更新某些共享數(shù)據(jù)時(shí),如溫度監(jiān)控、股票價(jià)格變化等。
觀察者模式的應(yīng)用
Spring的事件機(jī)制ApplicationEvent是事件對(duì)象,ApplicationListener是事件監(jiān)聽器,當(dāng)ApplicationEvent發(fā)布時(shí),所有注冊(cè)了該事件類型的ApplicationListener會(huì)被通知并處理該事件。ApplicationEventPublisher接口(通常是ApplicationContext的實(shí)現(xiàn)類)作為被觀察者,ApplicationListener作為觀察者。事件的發(fā)布和監(jiān)聽實(shí)現(xiàn)了松耦合的通知機(jī)制。
Java Web中的監(jiān)聽器,它通過(guò)監(jiān)聽和響應(yīng)Web應(yīng)用的生命周期事件、HTTP會(huì)話事件、請(qǐng)求事件以及屬性變化事件。常見的監(jiān)聽器接口包括ServletContextListener、HttpSessionListener、ServletRequestListener等,實(shí)現(xiàn)相應(yīng)的監(jiān)聽接口,即可完成相應(yīng)事件的監(jiān)聽。監(jiān)聽器機(jī)制的使用可以幫助開發(fā)者在特定事件發(fā)生時(shí)執(zhí)行一些處理邏輯,保證代碼的解耦和靈活性。
總結(jié)
觀察者模式是一種行為設(shè)計(jì)模式,其核心在于通過(guò)定義一對(duì)多的依賴關(guān)系,使得當(dāng)被觀察者的狀態(tài)發(fā)生變化時(shí),所有依賴的觀察者自動(dòng)收到通知并更新,從而實(shí)現(xiàn)對(duì)象之間的松耦合和動(dòng)態(tài)響應(yīng),同時(shí)便于觀察者的擴(kuò)展。

需要查看往期設(shè)計(jì)模式文章的,可以在個(gè)人主頁(yè)中或者文章開頭的集合中查看,可關(guān)注我,持續(xù)更新中。。。
超實(shí)用的SpringAOP實(shí)戰(zhàn)之日志記錄
通過(guò)軟考后卻領(lǐng)取不到實(shí)體證書?
計(jì)算機(jī)算法設(shè)計(jì)與分析(第5版)

浙公網(wǎng)安備 33010602011771號(hào)