螞蟻課堂第5期-網際網路架構-007:觀察者模式

競風之翼發表於2020-11-19

1 觀察者模式應用場景

課程內容:
1、什麼是觀察者、觀察者模式應用場景
2、觀察者實現的思路有那些
3、基於Jdk自帶觀察者模式實現訊息非同步傳輸
4、基於SpringBoot專案實現觀察者模式

什麼是觀察者模式
在物件之間定義了一對多的依賴,這樣一來,當一個物件改變狀態,依賴它的物件會收到通知並自動更新。
其實就是釋出訂閱模式,釋出者釋出資訊,訂閱者獲取資訊,訂閱了就能收到資訊,沒訂閱就收不到資訊。

觀察者模式應用場景
Zookeeper事件通知節點、訊息訂閱通知、安卓開發事件註冊、分散式配置中心

2 觀察者模式類圖原理

在這裡插入圖片描述

抽象主題(被觀察者):它把所有對觀察者物件的引用儲存在一個集合中,每個主題都可以有任意數量的觀察者。抽象主題提供一個介面,可以增加和刪除觀察者角色。
抽象觀察者:為所有的具體觀察者定義一個介面,在得到主題通知時更新自己。
具體主題(被觀察者):在具體主題的內部狀態改變時,向所有註冊過的觀察者發出通知。
具體觀察者:實現抽象觀察者角色的更新介面,一邊使本身的狀態與主題的狀態相協調。

3 純手寫Java觀察者模式

抽象觀察者

public interface Observer {

    /**
     * 通知觀察者訊息
     * @param message
     */
    void update(String message);
}

抽象主題

public interface AbstractSubject {

    /**
     * 新增觀察者 註冊觀察者
     *
     * @param observer
     */
    void addObserver(Observer observer);

    /**
     * 移除觀察者
     *
     * @param observer
     */
    void removeObserver(Observer observer);

    /**
     * 通知訊息
     *
     */
    void notifyObserver(String message);
}

具體主題

public class WeChatSubject implements AbstractSubject {

    // 如何存放這些主題
    private List<Observer> observerList = new ArrayList<>();

    @Override
    public void addObserver(Observer observer) {
        // 註冊或新增觀察者
        observerList.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observerList.remove(observer);
    }

    @Override
    public void notifyObserver(String message) {
        System.out.println("開始設定微信群發訊息:" + message);
        // 呼叫觀察者通知方法
        for (int i = 0; i < observerList.size(); i++) {
            Observer observer = observerList.get(i);
            // 呼叫該方法通知 獲取具體的訊息 群發
            observer.update(message);
        }
    }
}

具體觀察者

public class UserObserver implements Observer {

    private String name;

    public UserObserver(String name){
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + "老師收到訊息..");
    }
}

測試類

public class Test001 {
    public static void main(String[] args) {

        // 1.建立具體的主題
        AbstractSubject abstractSubject = new WeChatSubject();
        // 2.開始註冊或者新增觀察者
        abstractSubject.addObserver(new UserObserver("小薇"));
        abstractSubject.addObserver(new UserObserver("小敏"));
        // 3.群發訊息
        abstractSubject.notifyObserver("螞蟻課堂666..");
    }
}

執行結果
在這裡插入圖片描述

4 JDK觀察者模式原始碼分析

1.Observer(觀察者)
在這裡插入圖片描述
2.Observable(主題)追蹤所有的觀察者,並通知他們。
在這裡插入圖片描述

5 使用JDK觀察者群發訊息

自定義主題

public class MessageObservable extends Observable {

    @Override
    public void notifyObservers(Object arg) {
        // 1.修改狀態為可以群發
        setChanged();
        // 2.呼叫父類的notifyObservers 群發訊息
        super.notifyObservers(arg);
    }
}

自定義觀察者

public class SmsObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("使用者下單成功,傳送簡訊提醒內容:" + arg);
    }
}
public class EmailObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("使用者下單成功,傳送郵件提醒內容:" + arg);
    }
}
public class WechatObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("使用者下單成功,傳送微信提醒內容:" + arg);
    }
}

執行監聽開始

public class TestJdkObserver {
    public static void main(String[] args) {
        // 1.建立具體的主題
        Observable observable = new MessageObservable();
        // 2.註冊觀察者
        observable.addObserver(new SmsObserver());
        observable.addObserver(new EmailObserver());
        observable.addObserver(new WechatObserver());
        // 3.群發訊息
        observable.notifyObservers("恭喜您中獎!");
    }
}

測試結果:
在這裡插入圖片描述

注意:實際開發中具體觀察者中的方法要非同步處理,要單獨有執行緒去執行這段程式碼。

6 SpringBoot事件通知底層原理

Spring封裝事件監聽
Spring實現事件通知,底層是採用觀察者模式封裝的

下單訊息事件 OrderMessageEvent

public class OrderMessageEvent extends ApplicationEvent {

    /**
     * 群發訊息的內容
     */
    private JSONObject jsonObject;

    public OrderMessageEvent(Object source, JSONObject jsonObject) {
        super(source);
        this.jsonObject = jsonObject;
    }

    public JSONObject getJsonObject() {
        return jsonObject;
    }

    public void setJsonObject(JSONObject jsonObject) {
        this.jsonObject = jsonObject;
    }
}

事件監聽者 EmailListener/SmsListener

@Component
public class EmailListener implements ApplicationListener<OrderMessageEvent> {
    @Override
    @Async
    public void onApplicationEvent(OrderMessageEvent event) {
        // 如何獲取到當前容器下面所有的觀察者? 通過反射機制獲取ApplicationListener介面下面的子類
        System.out.println(Thread.currentThread().getName() + "開始傳送郵件訊息內容:" + event.getJsonObject().toString());
    }
}
@Component
public class SmsListener implements ApplicationListener<OrderMessageEvent> {
    @Override
    @Async
    public void onApplicationEvent(OrderMessageEvent event) {
        System.out.println(Thread.currentThread().getName() + "開始傳送簡訊訊息內容:" + event.getJsonObject().toString());

    }
}

控制層

@RestController
public class OrderController {

    @Autowired
    private ApplicationContext applicationContext;

    @RequestMapping("/sendMsg")
    public String sendMsg() {
        // 1.定義傳送訊息內容
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("email", "644064779@qq.com");
        jsonObject.put("phone", "15123456789");
        jsonObject.put("text", "恭喜您中獎!");
        OrderMessageEvent orderMessageEvent = new OrderMessageEvent(this, jsonObject);
        applicationContext.publishEvent(orderMessageEvent);
        return "success";

    }
}

啟動類

@SpringBootApplication
@EnableAsync
public class AppObserver {
    public static void main(String[] args) {
        SpringApplication.run(AppObserver.class);
    }
}

執行結果
在這裡插入圖片描述

相關文章