大氣的網(wǎng)站首頁google搜索引擎入口下載
觀察者模式由來
觀察者模式(Observer Pattern)是一種行為型設(shè)計模式,它的起源可以追溯到20世紀90年代初,由設(shè)計模式四人幫(Erich Gamma, Richard Helm, Ralph Johnson 和 John Vlissides)在其著作《設(shè)計模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》中首次提出。觀察者模式用于解決對象之間的一對多依賴關(guān)系,當一個對象(被觀察者)的狀態(tài)發(fā)生改變時,所有依賴于它的對象(觀察者)都會得到通知并自動更新。
概念
- 被觀察者(Subject):定義一個接口,用于添加、刪除和通知觀察者。
- 觀察者(Observer):定義一個接口,用于接收被觀察者的通知并執(zhí)行相應(yīng)的操作。
- 具體被觀察者(ConcreteSubject):實現(xiàn)被觀察者接口,維護觀察者列表,并在狀態(tài)改變時通知所有觀察者。
- 具體觀察者(ConcreteObserver):實現(xiàn)觀察者接口,具體實現(xiàn)接收到通知后的操作。
實現(xiàn)原理
觀察者模式的核心原理是通過將對象間的依賴關(guān)系從硬編碼轉(zhuǎn)移到外部,使得一個對象(被觀察者)可以在不通知其他對象的情況下更改其狀態(tài),然后在適當?shù)臅r候通知所有依賴于它的對象(觀察者)。這種解耦的設(shè)計方式使得代碼更加靈活,易于擴展和維護。
我有一個朋友張三,他總是關(guān)心天氣情況,每天會看天氣預(yù)報,在這個過程中,天氣預(yù)報(被觀察者)和張三(觀察者)之間就會存在一種依賴關(guān)系。當天氣預(yù)報發(fā)生變化時,張三需要得到通知并及時更新自己的信息。
定義角色:
- 被觀察者(Subject):天氣預(yù)報。它包含了當前的天氣狀況以及未來一段時間內(nèi)的天氣預(yù)報信息。
- 觀察者(Observer):張三。他是一個依賴于天氣預(yù)報信息的用戶。
建立依賴關(guān)系:
- 張三訂閱了天氣預(yù)報服務(wù),這樣當他打開電視或查看手機時,就能接收到最新的天氣預(yù)報信息。
事件通知機制:
- 天氣預(yù)報服務(wù)會在天氣狀況發(fā)生變化時,或者新的預(yù)報信息生成時,觸發(fā)通知機制。這個機制負責將最新的天氣信息發(fā)送給所有訂閱了服務(wù)的用戶,包括張三。
更新策略:
- 張三在接收到天氣預(yù)報信息后,會根據(jù)信息的內(nèi)容更新自己的認知,比如決定是否要帶傘、穿什么衣服等。
動態(tài)加入和退出:
- 如果張三決定不再訂閱天氣預(yù)報服務(wù),他可以隨時取消訂閱。同樣,如果張三從一個城市搬到另一個城市,他可以訂閱新的城市的天氣預(yù)報服務(wù)。
技術(shù)實現(xiàn)
首先,我們定義一個Subject
接口和一個Observer
接口:
// 被觀察者
public interface Subject {void registerObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers();
}// 觀察者
public interface Observer {void update(String message);
}
然后,我們創(chuàng)建一個WeatherForecast
類作為被觀察者,實現(xiàn)Subject
接口:
import java.util.ArrayList;
import java.util.List;public class WeatherForecast implements Subject {private List<Observer> observers = new ArrayList<>();private String message;public void setMessage(String message) {this.message = message;notifyObservers();}@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(message);}}
}
接下來,我們創(chuàng)建一個WeatherWatcher
類作為觀察者,實現(xiàn)Observer
接口:
public class WeatherWatcher implements Observer {private String name;public WeatherWatcher(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println(name + " received weather forecast: " + message);}
}
最后,我們在主函數(shù)中創(chuàng)建一個WeatherForecast
對象和兩個WeatherWatcher
對象,并讓它們訂閱天氣預(yù)報:
public static void main(String[] args) {WeatherForecast weatherForecast = new WeatherForecast();WeatherWatcher watcher1 = new WeatherWatcher("張三");WeatherWatcher watcher2 = new WeatherWatcher("李四");weatherForecast.registerObserver(watcher1);weatherForecast.registerObserver(watcher2);weatherForecast.setMessage("今天天氣晴朗,溫度適中。");weatherForecast.setMessage("明天將會有大雨,請攜帶雨具。");
}
運行這個程序,你會看到張三和李四都收到了天氣預(yù)報的通知。
Spring 實現(xiàn)
定義事件類:首先,我們需要定義一個事件類,它將攜帶被觀察者狀態(tài)變化的信息。
package com.neo.design.observer;import org.springframework.context.ApplicationEvent;public class WeatherEvent extends ApplicationEvent {private String weatherInfo;public WeatherEvent(Object source, String weatherInfo) {super(source);this.weatherInfo = weatherInfo;}public String getWeatherInfo() {return weatherInfo;}
}
- 創(chuàng)建事件發(fā)布者:接下來,我們創(chuàng)建一個事件發(fā)布者,它將負責發(fā)布天氣變更事件。在這個例子中,我們將使用Spring的
ApplicationEventPublisher
來發(fā)布事件。
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;@Component
public class WeatherEventPublisher {private final ApplicationEventPublisher publisher;public WeatherEventPublisher(ApplicationEventPublisher publisher) {this.publisher = publisher;}public void publishWeatherChangeEvent(String message) {publisher.publishEvent(new WeatherChangeEvent(message));}
}
創(chuàng)建事件監(jiān)聽器:然后,我們創(chuàng)建一個事件監(jiān)聽器,它將實現(xiàn)ApplicationListener
接口,并重寫onApplicationEvent
方法。在這個方法中,我們將處理天氣變更事件,并通知相關(guān)的觀察者。
package com.neo.design.observer;import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;@Component
public class WeatherEventPublisher {private final ApplicationEventPublisher publisher;public WeatherEventPublisher(ApplicationEventPublisher publisher) {this.publisher = publisher;}public void publishWeatherChangeEvent(String message) {publisher.publishEvent(new WeatherChangeEvent(message));}
}
創(chuàng)建用戶服務(wù):我們還需要創(chuàng)建一個用戶服務(wù),它將負責管理用戶的訂閱信息,并在接收到天氣變更事件時通知用戶。
package com.neo.design.observer;import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;@Service
public class UserService {private final List<String> subscribers = new ArrayList<>();public void subscribe(String subscriber) {subscribers.add(subscriber);}public void notifySubscribers(String message) {for (String subscriber : subscribers) {System.out.println(subscriber + " received weather forecast: " + message);}}
}
創(chuàng)建控制器:最后,我們創(chuàng)建一個控制器,它將接收用戶訂閱請求和天氣變更請求,并調(diào)用相應(yīng)的服務(wù)來處理這些請求。
package com.neo.design.observer;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class WeatherForecastController {@Autowiredprivate UserService userService;@Autowiredprivate WeatherEventPublisher publisher;@PostMapping("/subscribe")public String subscribe(@RequestParam("subscriber") String subscriber) {userService.subscribe(subscriber);return "Subscriber added!";}@PostMapping("/update-weather")public String updateWeather(@RequestParam("message") String message) {publisher.publishWeatherChangeEvent(message);return "Weather updated!";}
}
通過以上設(shè)計,我們利用Spring Boot的事件機制和依賴注入特性實現(xiàn)了一個高效的觀察者模式。
驗證
新增一名觀察者
設(shè)定一個被觀察者所關(guān)注的消息。
執(zhí)行功能,返回測試結(jié)果如下
總結(jié)
觀察者模式(Observer Pattern)在軟件工程設(shè)計中扮演著重要角色,觀察者模式實現(xiàn)了發(fā)布者(主題)和訂閱者(觀察者)之間的松散耦合。發(fā)布者無需知道具體的訂閱者是誰,只需要維護一個訂閱者列表,并在狀態(tài)變化時通知它們。這種解耦使得系統(tǒng)更具靈活性和可擴展性。通過觀察者模式,添加或移除訂閱者非常容易,不需要修改發(fā)布者的代碼。只需實現(xiàn)觀察者接口并注冊或取消注冊即可。這使得系統(tǒng)在需求變化或擴展時更易于維護。它適用于各種需要實時更新和異步處理的場景,提升了系統(tǒng)的響應(yīng)能力和用戶體驗,是設(shè)計模式中一個非常實用且常用的模式。
?
?
?