設計模式系列之觀察者模式
本文轉載自微信公眾號「狼王編程」,作者狼王 。轉載本文請聯系狼王編程公眾號。
大家好,我是狼王,一個愛打球的程序員
這篇讓我們來認識一下觀察者模式
1、概述
觀察者模式是一種行為設計模式, 允許你定義一種訂閱機制, 可在對象事件發生時通知多個 “觀察” 該對象的其他對象。
2、適用場景
1)當一個對象狀態的改變需要改變其他對象, 或實際對象是事先未知的或動態變化時, 可使用觀察者模式。
2) 當應用中的一些對象必須觀察其他對象時,可使用該模式。但僅能在有限時間內或特定情況下使用。訂閱者可隨時加入或離開該列表。
3、實例
有以下場景:
- 有一個小區,需要進行核酸檢測。
- 假設每個人通過關注公眾號獲取核酸檢測結果。
發布者接口:
- /**
- * 發布接口
- */
- public interface IPublisher {
- /**
- * 發布事件
- * @param event
- */
- void publish(IEvent event);
- }
訂閱者接口:
- /**
- * 通用訂閱接口
- */
- public interface ISubscriber {
- /**
- * 查看結果
- */
- void look();
- }
事件接口:
- /**
- * 通用事件接口
- */
- public interface IEvent {
- /**
- * 打印事件信息
- */
- void print();
- }
消息發送者
- /**
- * 消息發送者
- */
- public class Publisher implements IPublisher{
- private IEvent event;
- private List<ISubscriber> subscribers;
- public Publisher(IEvent event, List<ISubscriber> subscribers) {
- this.event = event;
- this.subscribers = subscribers;
- }
- /**
- * 發布消息
- * @param event
- */
- @Override
- public void publish(IEvent event){
- event.print();
- }
- public IEvent getEvent() {
- return event;
- }
- public void setEvent(IEvent event) {
- this.event = event;
- }
- public List<ISubscriber> getSubscribers() {
- return subscribers;
- }
- public void setSubscribers(List<ISubscriber> subscribers) {
- this.subscribers = subscribers;
- }
- }
事件:
- /**
- * 檢測事件
- */
- public class CheckEvent implements IEvent{
- private String name;
- private String result;
- private ISubscriber subscriber;
- public ISubscriber getSubscriber() {
- return subscriber;
- }
- public void setSubscriber(ISubscriber subscriber) {
- this.subscriber = subscriber;
- }
- public CheckEvent(String name) {
- this.name = name;
- }
- @Override
- public void print() {
- subscriber.look();
- System.out.println("事件名稱:" + name);
- System.out.println("事件結果:" + result);
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getResult() {
- return result;
- }
- public void setResult(String result) {
- this.result = result;
- }
- }
訂閱者:
- /**
- * 訂閱者
- */
- public class User implements ISubscriber{
- private String name;
- public User(String name) {
- this.name = name;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- @Override
- public void look() {
- System.out.println("檢測姓名:" + name);
- }
- }
客戶端:
- /**
- * 測試類
- */
- public class TestDemo {
- public static void main(String[] args) {
- //定義兩種結果
- String[] doc = {"陰性", "陽性"};
- //初始化檢測事件
- CheckEvent check = new CheckEvent("核酸檢測");
- //初始化消息發布者
- Publisher publisher = new Publisher(check,new ArrayList<>());
- //實例化接受檢測的用戶
- List<ISubscriber> users = new ArrayList<>();
- for (int i = 0; i < 10; i++) {
- //初始化用戶
- User user = new User("狼王" + i);
- users.add(user);
- }
- //用戶訂閱事件
- publisher.setSubscribers(users);
- int index;
- //發布檢測結果
- for (int i = 0; i < 10; i++) {
- System.out.println("---------------");
- //隨機檢測結果
- index = (int) (Math.random() * doc.length);
- check.setSubscriber(users.get(i));
- check.setResult(doc[index]);
- //發布
- publisher.publish(check);
- }
- }
- }
結果:
- ---------------
- 檢測姓名:狼王0
- 事件名稱:核酸檢測
- 事件結果:陰性
- ---------------
- 檢測姓名:狼王1
- 事件名稱:核酸檢測
- 事件結果:陰性
- ---------------
- 檢測姓名:狼王2
- 事件名稱:核酸檢測
- 事件結果:陽性
- ---------------
- 檢測姓名:狼王3
- 事件名稱:核酸檢測
- 事件結果:陰性
- ---------------
- 檢測姓名:狼王4
- 事件名稱:核酸檢測
- 事件結果:陽性
- ---------------
- 檢測姓名:狼王5
- 事件名稱:核酸檢測
- 事件結果:陽性
- ---------------
- 檢測姓名:狼王6
- 事件名稱:核酸檢測
- 事件結果:陽性
- ---------------
- 檢測姓名:狼王7
- 事件名稱:核酸檢測
- 事件結果:陰性
- ---------------
- 檢測姓名:狼王8
- 事件名稱:核酸檢測
- 事件結果:陰性
- ---------------
- 檢測姓名:狼王9
- 事件名稱:核酸檢測
- 事件結果:陰性
4、分析
代碼依賴關系如下圖所示:
分別定義了三個接口:事件接口,消息發布者接口,消息訂閱者接口每個接口有其對應的實現。
這樣設計利于后續的擴展,在不同的事件和不同的訂閱者以及消息發布者,都可以進行擴展而不影響其他。
5、總結
優點:
1)開閉原則
2)業務代碼解耦,具體消息訂閱者和發布者沒有直接關聯。
缺點:
1)多個消費者存在的時候,可能會無法控制順序和時間較長。
好了。今天就說到這了,我還會不斷分享自己的所學所想,希望我們一起走在成功的道路上!