国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

觀察者設(shè)計(jì)模式

這篇具有很好參考價(jià)值的文章主要介紹了觀察者設(shè)計(jì)模式。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

行為型設(shè)計(jì)模式

行為型模式(Behavioral Patterns):這類模式主要關(guān)注對(duì)象之間的通信。它們 分別是:

  • 職責(zé)鏈模式(Chain of Responsibility)
  • 命令模式(Command)
  • 解釋器模式(Interpreter)
  • 迭代器模式(Iterator)
  • 中介者模式(Mediator)
  • 備忘錄模式(Memento)
  • 觀察者模式(Observer)
  • 狀態(tài)模式(State)
  • 策略模式(Strategy)
  • 模板方法模式(Template Method)
  • 訪問者模式(Visitor)

1. 觀察者設(shè)計(jì)模式

1.1 概述

觀察者模式是一種行為設(shè)計(jì)模式,允許對(duì)象間存在一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴它的對(duì)象都會(huì)得到通知并自動(dòng)更新。在這種模式中,發(fā)生狀態(tài)改變的對(duì)象被稱為“主題”(Subject),依賴它的對(duì)象被稱為“觀察者”(Observer)。所以觀察者模式(Observer Design Pattern)也被稱為發(fā)布訂閱模式(Publish-Subscribe Design Pattern)。

被依賴的對(duì)象叫作被觀察者(Observable),依賴的對(duì)象叫作觀察者(Observer)。在實(shí)際的項(xiàng)目開發(fā)中,這兩種對(duì)象的稱呼是比較靈活的,有各種不同的叫法,比如:Subject-Observer、Publisher-Subscriber、Producer-Consumer等等。不管怎么稱呼,只要應(yīng)用場(chǎng)景符合剛剛給出的定義,都可以看作是觀察者模式。

我們通過一個(gè)例子來實(shí)現(xiàn)觀察者模式。假設(shè)我們有一個(gè)氣象站(WeatherStation),需要向許多不同的顯示設(shè)備(如手機(jī)App、網(wǎng)站、電子屏幕等)提供實(shí)時(shí)天氣數(shù)據(jù)。
觀察者設(shè)計(jì)模式,設(shè)計(jì)模式,設(shè)計(jì)模式,java
首先,我們需要?jiǎng)?chuàng)建一個(gè)Subject接口,表示被觀察的主題:

/**
 * 接口描述:被觀察者應(yīng)該提供注冊(cè)、刪除、通知觀察者的能力
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/1 21:43
 */
public interface Subject {

    /**
     * 注冊(cè)觀察者
     *
     * @param observer
     */
    void registerObserver(Observer observer);

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

    /**
     * 通知觀察者
     */
    void notifyObservers();
}

接下來,我們創(chuàng)建一個(gè)Observer接口,表示依賴主題的觀察者接口:

/**
 * 接口描述:觀察者接口
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/1 21:50
 */
public interface Observer {
    /**
     * 更新新的天氣氣溫
     *
     * @param temperature
     */
    void update(float temperature);
}

創(chuàng)建一個(gè)具體的主題,如WeatherStation,實(shí)現(xiàn)Subject接口:

/**
 * 類描述:氣象站(被觀察者)
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/1 21:49
 */
public class WeatherStation implements Subject {
    // 溫度
    private float temperature;
	// 所有依賴的觀察者
    private List<Observer> observers = new ArrayList<>();
	// 修改溫度
    public void changeTemperature(float temperature) {
        this.temperature = temperature;
        // 通知所有觀察者更新溫度
        notifyObservers();
    }

    @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);
        }
    }
}

最后,我們創(chuàng)建具體的觀察者并實(shí)現(xiàn)Observer接口,如AppClient、WebClient:

/**
 * 類描述:手機(jī)客戶端
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/1 21:55
 */
@Slf4j
public class AppClient implements Observer {
    @Override
    public void update(float temperature) {
        log.info("app更新了溫度,現(xiàn)在的溫度是: {}", temperature);
    }
}

/**
 * 類描述:網(wǎng)頁客戶端
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/1 21:57
 */
@Slf4j
public class WebClient implements Observer {
    @Override
    public void update(float temperature) {
        log.info("網(wǎng)頁客戶端更新了氣溫,溫度是:{}", temperature);
    }
}

測(cè)試用例:

/**
 * 類描述:觀察者設(shè)計(jì)模式測(cè)試案例
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/1 21:57
 */
public class ObserverTest {
    @Test
    public void test() {
        // 定義氣象站(主題-被觀察者)
        WeatherStation weatherStation = new WeatherStation();
        // 定義觀察者客戶端(觀察者)
        Observer appClient = new AppClient();
        Observer webClient = new WebClient();
        // 注冊(cè)觀察者
        weatherStation.registerObserver(appClient);
        weatherStation.registerObserver(webClient);

        // 更新溫度
        weatherStation.changeTemperature(20.05f);
    }
}

測(cè)試結(jié)果:

[main] INFO cn.itcast.designPatterns.observer.weather.AppClient - app更新了溫度,現(xiàn)在的溫度是: 20.05
[main] INFO cn.itcast.designPatterns.observer.weather.WebClient - 網(wǎng)頁客戶端更新了氣溫,溫度是:20.05

使用觀察者模式的優(yōu)點(diǎn):

  • 觀察者和主題之間的解耦:主題只需要知道觀察者實(shí)現(xiàn)了Observer接口,而無需了解具體的實(shí)現(xiàn)細(xì)節(jié)。提高代碼的可維護(hù)性和可擴(kuò)展性。
  • 可以動(dòng)態(tài)添加和刪除觀察者:通過調(diào)用registerObserver和removeObserver方法,可以在運(yùn)行時(shí)添加和刪除觀察者。
  • 主題和觀察者之間的通信是自動(dòng)的:當(dāng)主題的狀態(tài)發(fā)生變化時(shí),觀察者會(huì)自動(dòng)得到通知并更新自己的狀態(tài)。

上面的小例子算是觀察者模式的“模板代碼”,可以反映該模式大體的設(shè)計(jì)思路。在真實(shí)的軟件開發(fā)中,并不需要照搬上面的模板代碼。觀察者模式的實(shí)現(xiàn)方法各式各樣,函數(shù)、類的命名等會(huì)根據(jù)業(yè)務(wù)場(chǎng)景的不同有很大的差別,比如 register 函數(shù)還可以叫作 attach,remove 函數(shù)還可以叫作 detach 等等。不過,萬變不離其宗,設(shè)計(jì)思路都是差不多的。

了解了觀察者設(shè)計(jì)模式的基本使用方式,我們接下來看看他的具體使用場(chǎng)景。

1.2 使用場(chǎng)景

以下是一些使用觀察者設(shè)計(jì)模式的例子:

  • 股票行情應(yīng)用:股票價(jià)格更新可以作為被觀察者,投資者可以作為觀察者。當(dāng)股票價(jià)格發(fā)生變化時(shí),所有訂閱了該股票的投資者都會(huì)收到通知并更新自己的投資策略。

  • 網(wǎng)絡(luò)聊天室:聊天室服務(wù)器可以作為被觀察者,用戶可以作為察者。當(dāng)有新消息時(shí),聊天室服務(wù)器會(huì)通知所有在線用戶更新聊天記錄。

  • 拍賣系統(tǒng):拍賣系統(tǒng)可以作為被觀察者,用戶可以作為觀察者。當(dāng)出價(jià)發(fā)生變化時(shí),所有關(guān)注該拍品的用戶都會(huì)收到通知并更新自己的出價(jià)策略。

  • 訂閱系統(tǒng):內(nèi)容發(fā)布可以作為被觀察者,用戶可以作為觀察者。當(dāng)有新內(nèi)容發(fā)布時(shí),所有訂閱了該內(nèi)容的用戶都會(huì)收到通知并獲取最新內(nèi)容。

  • 電子郵件通知系統(tǒng):任務(wù)狀態(tài)更新可以作為被觀察者,相關(guān)人員可以作為觀察者。當(dāng)任務(wù)狀態(tài)發(fā)生變化時(shí),所有關(guān)注該任務(wù)的人員都會(huì)收到通知并查看任務(wù)詳情。

  • 社交網(wǎng)絡(luò):被關(guān)注的用戶可以作為被觀察者,關(guān)注者可以作為觀察者。當(dāng)被關(guān)注的用戶發(fā)布新動(dòng)態(tài)時(shí),所有關(guān)注者都會(huì)收到通知并查看動(dòng)態(tài)。

1.3 發(fā)布訂閱

發(fā)布-訂閱模式觀察者模式都是用于實(shí)現(xiàn)對(duì)象間的松耦合通信的設(shè)計(jì)模式。盡管它們具有相似之處,但它們?cè)趯?shí)現(xiàn)方式和使用場(chǎng)景上存在一些關(guān)鍵區(qū)別。他們?cè)诟拍钌嫌幸欢ǖ南嗨菩?,都是用于?shí)現(xiàn)對(duì)象間的松耦合通信。可以將發(fā)布-訂閱模式看作是觀察者模式的一種變體或擴(kuò)展。

觀察者模式定義了一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象(被觀察者)的狀態(tài)發(fā)生變化時(shí),所有依賴于它的對(duì)象(觀察者)都會(huì)得到通知并自動(dòng)更新。在這個(gè)模式中,被觀察者和觀察者之間存在直接的關(guān)聯(lián)關(guān)系。觀察者模式主要包括兩類對(duì)象:被觀察者(Subject)和觀察者(Observer)。

發(fā)布-訂閱模式(生產(chǎn)者和消費(fèi)者)引入了第三方組件(通常稱為消息代理或事件總線),該組件負(fù)責(zé)維護(hù)發(fā)布者和訂閱者之間的關(guān)系。這意味著發(fā)布者和訂閱者彼此不直接通信,而是通過消息代理進(jìn)行通信。這種間接通信允許發(fā)布者和訂閱者在運(yùn)行時(shí)動(dòng)態(tài)地添加或刪除,從而提高了系統(tǒng)的靈活性和可擴(kuò)展性。

Java中的發(fā)布-訂閱模式示例:

// 訂閱者接口
public interface Subscriber {
    /**
     * 接收事件通知
     *
     * @param event
     */
    void onEvent(String event);
}

// 具體的訂閱者
@Slf4j
public class ConcreteSubscriber implements Subscriber {

    @Override
    public void onEvent(String event) {
        log.info("ConcreteSubscriber收到事件: {}", event);
    }
}

// 具體的訂閱者2
@Slf4j
public class ConcreteSubscriber2 implements Subscriber {

    @Override
    public void onEvent(String event) {
        log.info("ConcreteSubscriber2收到事件: {}", event);
    }
}

訂閱者與事件發(fā)布之間通過消息總線(代理)來聯(lián)系.

/**
 * 類描述:消息總線(代理),實(shí)現(xiàn)主題(事件)發(fā)布,注冊(cè)訂閱者,刪除訂閱者等
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/3 22:17
 */
public class EventBus {
    // 使用一個(gè)map維護(hù),消息類型和該消息的訂閱者
    private Map<String, List<Subscriber>> subscribers = new HashMap<>();

    /**
     * 訂閱消息
     *
     * @param eventType  事件類型
     * @param subscriber 訂閱者
     */
    public void subscribe(String eventType, Subscriber subscriber) {
        List<Subscriber> subs = subscribers.get(eventType);
        if (subs == null) {
            subs = new ArrayList<>();
        }
        subs.add(subscriber);

        subscribers.put(eventType, subs);
    }

    /**
     * 刪除訂閱
     *
     * @param eventType
     * @param subscriber
     */
    public void unSubscribe(String eventType, Subscriber subscriber) {
        List<Subscriber> subs = subscribers.get(eventType);
        if (subs != null) {
            subs.remove(subscriber);
        }
    }

    /**
     * 發(fā)布事件消息
     *
     * @param eventType
     * @param event
     */
    public void publish(String eventType, String event) {
        List<Subscriber> subs = subscribers.get(eventType);
        if (subs != null) {
            for (Subscriber sub : subs) {
                sub.onEvent(event);
            }
        }
    }
}

發(fā)布訂閱的測(cè)試案例

@Test
public void test2() {
    // 創(chuàng)建消息代理
    EventBus eventBus = new EventBus();
    // 創(chuàng)建訂閱者
    Subscriber subscriber = new ConcreteSubscriber();
    Subscriber subscriber2 = new ConcreteSubscriber2();

    // 訂閱事件
    String eventType = "eventA";
    eventBus.subscribe(eventType, subscriber);
    eventBus.subscribe(eventType, subscriber2);

    // 發(fā)布事件
    eventBus.publish(eventType, "這是事件A發(fā)布的消息");

    log.info("===============================================");

    // 取消訂閱
    eventBus.unSubscribe(eventType, subscriber2);

    // 再次發(fā)布事件
    eventBus.publish(eventType, "事件A又來發(fā)布的消息again");

}

測(cè)試結(jié)果:

[main] INFO cn.itcast.designPatterns.observer.subscriber.ConcreteSubscriber - ConcreteSubscriber收到事件: 這是事件A發(fā)布的消息
[main] INFO cn.itcast.designPatterns.observer.subscriber.ConcreteSubscriber2 - ConcreteSubscriber2收到事件: 這是事件A發(fā)布的消息
[main] INFO cn.itcast.designPattern.ObserverTest - ===============================================
[main] INFO cn.itcast.designPatterns.observer.subscriber.ConcreteSubscriber - ConcreteSubscriber收到事件: 事件A又來發(fā)布的消息again

總結(jié)一下兩者的區(qū)別:

  • 通信方式:觀察者模式中,觀察者與被觀察者之間存在直接的關(guān)聯(lián)關(guān)系,而發(fā)布-訂閱模式中,發(fā)布者和訂閱者通過一個(gè)第三方組件(消息代理或事件總線)進(jìn)行通信,彼此之間不存在直接關(guān)聯(lián)關(guān)系。
  • 系統(tǒng)復(fù)雜性:發(fā)布-訂閱模式引入了一個(gè)額外的組件(消息代理或事件總線),增加了系統(tǒng)的復(fù)雜性,但同時(shí)也提高了系統(tǒng)的靈活性和可擴(kuò)展性。
  • 使用場(chǎng)景:觀察者模式適用于需要將狀態(tài)變化通知給其他對(duì)象的情況,而發(fā)布-訂閱模式適用于事件驅(qū)動(dòng)的系統(tǒng),尤其是那些需要跨越多個(gè)模塊或組件進(jìn)行通信的場(chǎng)景。

發(fā)布-訂閱模式的優(yōu)點(diǎn):

  • 解耦:在發(fā)布-訂閱模式中,發(fā)布者和訂閱者之間沒有直接關(guān)聯(lián),它們通過一個(gè)中間組件(消息代理或事件總線)進(jìn)行通信。這種間接通信可以使發(fā)布者和訂閱者在運(yùn)行時(shí)動(dòng)態(tài)地添加或刪除,從而進(jìn)一步降低了它們之間的耦合度。

  • 可擴(kuò)展性:發(fā)布-訂閱模式更容易向系統(tǒng)中添加新的發(fā)布者和訂閱者,而無需修改現(xiàn)有的代碼。這使得系統(tǒng)在不同組件之間通信時(shí)具有更好的可擴(kuò)展性。

  • 模塊化:由于發(fā)布者和訂閱者之間的通信通過中間組件進(jìn)行,可以將系統(tǒng)劃分為更小、更獨(dú)立的模塊。這有助于提高代碼的可維護(hù)性和可讀性。

  • 異步通信:發(fā)布-訂閱模式通常支持異步消息傳遞,這意味著發(fā)布者和訂閱者可以在不同的線程或進(jìn)程中運(yùn)行。這有助于提高系統(tǒng)的并發(fā)性能和響應(yīng)能力。

  • 消息過濾:在發(fā)布-訂閱模式中,可以利用中間組件對(duì)消息進(jìn)行過濾,使得訂閱者只接收到感興趣的消息。這可以提高系統(tǒng)的性能,減少不必要的通信開銷。

發(fā)布-訂閱模式也有一些缺點(diǎn),例如增加了系統(tǒng)的復(fù)雜性,因?yàn)橐肓祟~外的中間組件。根據(jù)具體的應(yīng)用場(chǎng)景和需求來選擇合適的設(shè)計(jì)模式。

1.4 源碼使用

1.4.1 jdk中的觀察者

java.util.Observable類實(shí)現(xiàn)了主題(Subject)的功能,而java.util.Observer接口則定義了觀察者(Observer)的方法。

通過調(diào)用Observable對(duì)象的notifyObservers()方法,可以通知所有注冊(cè)的Observer對(duì)象,讓它們更新自己的狀態(tài)。

案例:假設(shè)有一個(gè)銀行賬戶類,它的余額是可變的。當(dāng)余額發(fā)生變化時(shí),需要通知所有的觀察者(比如說銀行客戶),以便它們更新自己的顯示信息。

使用觀察者模式來實(shí)現(xiàn)銀行客戶對(duì)自己賬戶余額的實(shí)時(shí)監(jiān)控。

首先創(chuàng)建主題類,實(shí)現(xiàn)存款,取款,獲取余額,注冊(cè)訂閱者,刪除訂閱者等

package cn.itcast.designPatterns.observer.jdkimpl;

import java.util.Observable;

/**
 * 類描述:銀行賬戶類,實(shí)現(xiàn)Observable類
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/9 21:37
 */
public class BankAccount extends Observable {

    /**
     * 余額
     */
    private double balance;

    public BankAccount(double balance) {
        this.balance = balance;
    }

    /**
     * 獲取當(dāng)前余額
     *
     * @return
     */
    public double getBalance() {
        return balance;
    }

    /**
     * 存款操作
     *
     * @param amount
     */
    public void deposit(double amount) {
        balance += amount;
        // 繼承下來的方法,表示狀態(tài)發(fā)生改變
        setChanged();
        // 繼承下來的方法,通知所有觀察者
        notifyObservers();
    }

    /**
     * 取款操作
     *
     * @param amount
     */
    public void withdraw(double amount) {
        balance -= amount;
        setChanged();
        notifyObservers();
    }
}

再創(chuàng)建觀察者類, 訂閱者

/**
 * 類描述:銀行客戶1-觀察者
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/9 21:45
 */
@Slf4j
public class ClientOberver implements Observer {

    @Override
    public void update(Observable observable, Object arg) {
        log.info("客戶1查看余額已更新為: {}", ((BankAccount) observable).getBalance());
    }
}

/**
 * 類描述:銀行客戶2-觀察者
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/9 21:45
 */
@Slf4j
public class ClientOberver2 implements Observer {

    @Override
    public void update(Observable observable, Object arg) {
        log.info("客戶2查看余額已更新為: {}", ((BankAccount) observable).getBalance());
    }
}

測(cè)試用例:

/**
 * 測(cè)試jdk中觀察者模式的實(shí)現(xiàn)
 */
@Test
public void test3() {
    // 創(chuàng)建發(fā)布事件(主題)對(duì)象
    BankAccount bankAccount = new BankAccount(100.00);

    log.info("銀行賬戶余額是:{}", bankAccount.getBalance());
    // 創(chuàng)建訂閱者
    ClientOberver clientOberver = new ClientOberver();
    ClientOberver2 clientOberver2 = new ClientOberver2();
    // 注冊(cè)訂閱者
    bankAccount.addObserver(clientOberver);
    bankAccount.addObserver(clientOberver2);
    // 存款50
    bankAccount.deposit(50.00);
    log.info("================================");
    // 取款25
    bankAccount.withdraw(25.00);
    log.info("================================");
    // 刪除訂閱者
    bankAccount.deleteObserver(clientOberver2);
    log.info("================================");
    // 取款20
    bankAccount.withdraw(20.00);
}

測(cè)試結(jié)果:

[main] INFO cn.itcast.designPattern.ObserverTest - 銀行賬戶余額是:100.0
[main] INFO cn.itcast.designPatterns.observer.jdkimpl.ClientOberver2 - 客戶2查看余額已更新為: 150.0
[main] INFO cn.itcast.designPatterns.observer.jdkimpl.ClientOberver - 客戶1查看余額已更新為: 150.0
[main] INFO cn.itcast.designPattern.ObserverTest - ================================
[main] INFO cn.itcast.designPatterns.observer.jdkimpl.ClientOberver2 - 客戶2查看余額已更新為: 125.0
[main] INFO cn.itcast.designPatterns.observer.jdkimpl.ClientOberver - 客戶1查看余額已更新為: 125.0
[main] INFO cn.itcast.designPattern.ObserverTest - ================================
[main] INFO cn.itcast.designPattern.ObserverTest - ================================
[main] INFO cn.itcast.designPatterns.observer.jdkimpl.ClientOberver - 客戶1查看余額已更新為: 105.0

這個(gè)案例中,BankAccount類繼承了java.util.Observable類,表示它是一個(gè)主題(Subject)。在存款或取款操作時(shí),它會(huì)調(diào)用setChanged()方法表示狀態(tài)已經(jīng)改變,并調(diào)用notifyObservers()方法通知所有觀察者(Observer)。

兩個(gè)觀察者(clientOberver和clientOberver2),它們分別實(shí)現(xiàn)了Observer接口的update()方法。當(dāng)觀察者收到更新通知時(shí),它們會(huì)執(zhí)行自己的業(yè)務(wù)邏輯,比如更新顯示信息。

1.4.2 Guava中的消息總線

Guava 庫中的 EventBus 類提供了一個(gè)簡(jiǎn)單的消息總線實(shí)現(xiàn),可以幫助您在 Java應(yīng)用程序中實(shí)現(xiàn)發(fā)布-訂閱模式。以下是一個(gè)簡(jiǎn)單的示例,演示了如何使用 Guava 的EventBus 來實(shí)現(xiàn)一個(gè)簡(jiǎn)單的消息發(fā)布和訂閱功能。

添加依賴項(xiàng):

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.1-jre</version>
</dependency>

定義一個(gè)事件消息類

/**
 * 類描述:事件消息類
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/9 22:02
 */
public class MessageEvent {

    private String message;

    public MessageEvent(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

創(chuàng)建一個(gè)訂閱者類。在訂閱者類中,定義一個(gè)方法并使用 @Subscribe 注解標(biāo)記該方法,以便 EventBus 能夠識(shí)別該方法作為事件處理器:

/**
 * 類描述:訂閱者類
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/9 22:03
 */
@Slf4j
public class MessageSubscriber {
    @Subscribe
    public void handleMessageEvent(MessageEvent event) {
        log.info("收到消息: {}", event.getMessage());
    }
}

測(cè)試用例:

/**
 * 測(cè)試guava的發(fā)布訂閱實(shí)現(xiàn)
 */
@Test
public void test4() {
    // 創(chuàng)建 EventBus 事件實(shí)例
    com.google.common.eventbus.EventBus eventBus = new com.google.common.eventbus.EventBus();
    // 創(chuàng)建并注冊(cè)訂閱者
    MessageSubscriber messageSubscriber = new MessageSubscriber();
    eventBus.register(messageSubscriber);
    // 發(fā)布事件
    eventBus.post(new MessageEvent("Hello, EventBus!"));
    // 刪除訂閱者
    eventBus.unregister(messageSubscriber);
    // 再次發(fā)布事件(此時(shí)訂閱者已取消注冊(cè),將不會(huì)收到消息)
    eventBus.post(new MessageEvent("Another message"));
}

在這個(gè)示例中,我們創(chuàng)建了一個(gè) EventBus 實(shí)例,然后創(chuàng)建并注冊(cè)了一個(gè)MessageSubscriber 類型的訂閱者。當(dāng)我們使用 eventBus.post() 方法發(fā)布一個(gè) MessageEvent 事件時(shí),訂閱者的 handleMessageEvent 方法將被調(diào)用,并輸出收到的消息。

注意,如果訂閱者處理事件的方法拋出異常, EventBus 默認(rèn)情況下不會(huì)對(duì)異常進(jìn)行處理。如果需要處理異常,可以在創(chuàng)建 EventBus 實(shí)例時(shí)傳入一個(gè)自定義的SubscriberExceptionHandler。

public class EventBus {
    public EventBus(SubscriberExceptionHandler exceptionHandler) {
        this("default", MoreExecutors.directExecutor(), Dispatcher.perThreadDispatchQueue(), exceptionHandler);
    }
}    

public interface SubscriberExceptionHandler {
    void handleException(Throwable var1, SubscriberExceptionContext var2);
}

1.5 進(jìn)階

之前講到的實(shí)現(xiàn)方式,是一種同步阻塞的實(shí)現(xiàn)方式。觀察者和被觀察者代碼在同一個(gè)線程內(nèi)執(zhí)行,被觀察者一直阻塞,直到所有的觀察者代碼都執(zhí)行完成之后,才執(zhí)行后續(xù)的代碼。

如果注冊(cè)接口是一個(gè)調(diào)用比較頻繁的接口,對(duì)性能非常敏感,希望接口的響應(yīng)時(shí)間盡可能短,那我們可以將同步阻塞的實(shí)現(xiàn)方式改為異步非阻塞的實(shí)現(xiàn)方式,以此來減少響應(yīng)時(shí)間。

1.5.1 異步非阻塞模型

創(chuàng)建主題接口及實(shí)現(xiàn)

/**
 * 接口描述:主題類(發(fā)布事件等)
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/10 21:35
 */
public interface SyncObservable {
    /**
     * 注冊(cè)觀察者
     *
     * @param observer
     */
    void addObserver(SyncObserver observer);

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

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

/**
 * 類描述:具體的主題實(shí)現(xiàn)類(異步通知觀察者)
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/10 21:37
 */
public class SyncObservableImpl implements SyncObservable {
    private List<SyncObserver> observers;
    private ExecutorService executorService;

    public SyncObservableImpl() {
        observers = new ArrayList<>();
        executorService = Executors.newCachedThreadPool();
    }

    /**
     * 消息更新后,通知所有觀察者
     *
     * @param message
     */
    public void setMessage(String message) {
        notifyObservers(message);
    }

    @Override
    public void addObserver(SyncObserver observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(SyncObserver observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers(String message) {
        for (SyncObserver observer : observers) {
            // 異步執(zhí)行
            executorService.submit(() -> observer.update(message));
        }

    }
}

創(chuàng)建觀察者接口及實(shí)現(xiàn)

/**
 * 接口描述:觀察者接口
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/10 21:34
 */
public interface SyncObserver {
    void update(String message);
}

/**
 * 類描述:
 *
 * @Author crysw
 * @Version 1.0
 * @Date 2024/1/10 21:36
 */
@Slf4j
public class SyncObserverImpl implements SyncObserver {
    private String name;

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

    @Override
    public void update(String message) {
        log.info("{} received message: {}", name, message);
    }
}

測(cè)試用例:

/**
 * 測(cè)試異步通知
 */
@Test
public void test5() {
    // 創(chuàng)建主題(發(fā)布事件)對(duì)象
    SyncObservableImpl observable = new SyncObservableImpl();
    // 創(chuàng)建觀察者
    SyncObserver observer = new SyncObserverImpl("crysw");
    SyncObserver observer2 = new SyncObserverImpl("paanda");
    // 注冊(cè)觀察者
    observable.addObserver(observer);
    observable.addObserver(observer2);
    // 發(fā)布消息
    observable.setMessage("放假了,放假了");
    // 移除觀察者
    observable.removeObserver(observer);
    // 再次更新消息
    observable.setMessage("錯(cuò)了,繼續(xù)搬磚");
}

1.5.2 跨進(jìn)程通信

不管是同步阻塞實(shí)現(xiàn)方式還是異步非阻塞實(shí)現(xiàn)方式,都是進(jìn)程內(nèi)的實(shí)現(xiàn)方式。如果用戶注冊(cè)成功之后,需要發(fā)送用戶信息給大數(shù)據(jù)征信系統(tǒng),而大數(shù)據(jù)征信系統(tǒng)是一個(gè)獨(dú)立的系統(tǒng),跟它之間的交互是跨不同進(jìn)程的,那如何實(shí)現(xiàn)一個(gè)跨進(jìn)程的觀察者模式呢?

如果大數(shù)據(jù)征信系統(tǒng)提供了發(fā)送用戶注冊(cè)信息的 RPC 接口,我們?nèi)匀豢梢匝赜弥暗膶?shí)現(xiàn)思路,在 notifyObservers() 函數(shù)中調(diào)用 RPC 接口來發(fā)送數(shù)據(jù)。但是,我們還有更加常用的一種實(shí)現(xiàn)方式,那就是基于消息隊(duì)列(Message Queue)來實(shí)現(xiàn)。

當(dāng)然,這種實(shí)現(xiàn)方式也有弊端,需要引入一個(gè)新的系統(tǒng)(消息隊(duì)列),增加了維護(hù)成本。不過,它的好處也非常明顯。在原來的實(shí)現(xiàn)方式中,觀察者需要注冊(cè)到被觀察者中,被觀察者需要依次遍歷觀察者來發(fā)送消息。而基于消息隊(duì)列的實(shí)現(xiàn)方式,被觀察者和觀察者解耦更加徹底,兩部分的耦合更小。被觀察者完全不感知觀察者,同理,觀察者也完全不感知被觀察者。被觀察者只管發(fā)送消息到消息隊(duì)列,觀察者只管從消息隊(duì)列中讀取消息來執(zhí)行相應(yīng)的邏輯。文章來源地址http://www.zghlxwxcb.cn/news/detail-821413.html

到了這里,關(guān)于觀察者設(shè)計(jì)模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Java設(shè)計(jì)模式-觀察者模式-SpringBoot實(shí)現(xiàn)

    Java設(shè)計(jì)模式-觀察者模式-SpringBoot實(shí)現(xiàn)

    項(xiàng)目:https://gitee.com/KakarottoChen/blog-code.git 的:JavaSpringListener Java觀察者模式是一種設(shè)計(jì)模式,用于實(shí)現(xiàn)對(duì)象之間的一對(duì)多依賴關(guān)系。在觀察者模式中,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生變化時(shí),它的所有依賴對(duì)象(觀察者)都會(huì)自動(dòng)收到通知并進(jìn)行相應(yīng)的更新。 觀察者模式由以下幾個(gè)核

    2024年02月08日
    瀏覽(89)
  • java設(shè)計(jì)模式-觀察者模式(jdk內(nèi)置)

    上一篇我們學(xué)習(xí)了 觀察者模式。 觀察者和被觀察者接口都是我們自己定義的,整個(gè)設(shè)計(jì)模式我們從無到有都是自己設(shè)計(jì)的,其實(shí),java已經(jīng)內(nèi)置了這個(gè)設(shè)計(jì)模式,我們只需要定義實(shí)現(xiàn)類即可。 下面我們不多說明,直接示例代碼,例子依然同 觀察者模式篇章,建議先去看看。

    2024年02月15日
    瀏覽(23)
  • Java設(shè)計(jì)模式系列--觀察者模式寫法2:JDK

    Java設(shè)計(jì)模式系列--觀察者模式寫法2:JDK

    原文網(wǎng)址:Java設(shè)計(jì)模式系列--觀察者模式寫法2:JDK_IT利刃出鞘的博客-CSDN博客 說明 本文用示例介紹觀察者模式的一種寫法:JDK。 JDK的觀察者模式簡(jiǎn)介 在 Java 中,java.util.Observable 類和 java.util.Observer 接口定義了觀察者模式,只要實(shí)現(xiàn)這兩個(gè)接口就可以編寫觀察者模式。 1. Ob

    2024年02月13日
    瀏覽(23)
  • 【設(shè)計(jì)模式——學(xué)習(xí)筆記】23種設(shè)計(jì)模式——觀察者模式Observer(原理講解+應(yīng)用場(chǎng)景介紹+案例介紹+Java代碼實(shí)現(xiàn))

    【設(shè)計(jì)模式——學(xué)習(xí)筆記】23種設(shè)計(jì)模式——觀察者模式Observer(原理講解+應(yīng)用場(chǎng)景介紹+案例介紹+Java代碼實(shí)現(xiàn))

    有一個(gè)天氣預(yù)報(bào)項(xiàng)目,需求如下: 氣象站可以將每天測(cè)量到的溫度、濕度、氣壓等等以公告的形式發(fā)布出去(比如發(fā)布到自己的網(wǎng)站或第三方) 需要設(shè)計(jì)開放型API,便于其他第三方也能接入氣象站獲取數(shù)據(jù) 提供溫度、氣壓、濕度的接口 測(cè)量數(shù)據(jù)更新時(shí),要能實(shí)時(shí)的通知給第三

    2024年02月14日
    瀏覽(20)
  • 設(shè)計(jì)模式——觀察者模式

    設(shè)計(jì)模式——觀察者模式

    觀察者模式可以分為觀察者和被觀察者,觀察者通過注冊(cè)到一個(gè)被觀察者中,也可視為訂閱,當(dāng)被觀察者的數(shù)據(jù)發(fā)生改變時(shí),會(huì)通知到觀察者,觀察者可以據(jù)此做出反應(yīng)。 可以類比訂閱報(bào)紙,報(bào)社就是被觀察者,訂閱者就是觀察者,訂閱者通過訂閱報(bào)紙與報(bào)社建立聯(lián)系,而報(bào)

    2024年02月15日
    瀏覽(17)
  • 【設(shè)計(jì)模式】觀察者模式

    【設(shè)計(jì)模式】觀察者模式

    觀察者模式(又被稱為發(fā)布-訂閱(Publish/Subscribe)模式,屬于行為型模式的一種,它定義了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象。這個(gè)主題對(duì)象在狀態(tài)變化時(shí),會(huì)通知所有的觀察者對(duì)象,使他們能夠自動(dòng)更新自己。 Subject:抽象主題(被觀察者

    2024年02月13日
    瀏覽(20)
  • 設(shè)計(jì)模式---觀察者模式

    1,概念 ????????屬于行為模式的一種,定義了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一對(duì)象主題對(duì)象,這個(gè)主題對(duì)象在狀態(tài)變化時(shí),會(huì)通知所有的觀察者對(duì)象,使他們能夠自動(dòng)更新自己。 在觀察者模式中有如下角色: Subject:抽象主題(抽象被觀察者),

    2024年02月15日
    瀏覽(18)
  • 設(shè)計(jì)模式-觀察者模式

    觀察者模式是一種行為型設(shè)計(jì)模式,它定義了一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),其所有依賴者都會(huì)收到通知并自動(dòng)更新。當(dāng)對(duì)象間存在一對(duì)多關(guān)系時(shí),則使用觀察者模式(Observer Pattern)。比如,當(dāng)一個(gè)對(duì)象被修改時(shí),則會(huì)自動(dòng)通知依賴它的對(duì)象。觀察者

    2024年02月15日
    瀏覽(22)
  • 設(shè)計(jì)模式:觀察者模式

    定義 觀察者模式(Observer Pattern)是一種行為設(shè)計(jì)模式,允許一個(gè)對(duì)象(稱為“主題”或“可觀察對(duì)象”)維護(hù)一組依賴于它的對(duì)象(稱為“觀察者”),當(dāng)主題的狀態(tài)發(fā)生變化時(shí),會(huì)自動(dòng)通知所有觀察者對(duì)象。 應(yīng)用場(chǎng)景 觀察者模式適用于以下場(chǎng)景: 聯(lián)動(dòng)反應(yīng) :當(dāng)一個(gè)對(duì)象

    2024年04月08日
    瀏覽(24)
  • 設(shè)計(jì)模式之觀察者模式

    可以幫你的對(duì)象知悉現(xiàn)況,不會(huì)錯(cuò)過該對(duì)象感興趣的事。對(duì)象甚至在運(yùn)行時(shí)可決定是否要繼續(xù)被通知。 從報(bào)紙和雜志的訂閱說起: 報(bào)社的業(yè)務(wù)就是出版報(bào)紙 向某家報(bào)社訂閱報(bào)紙,只要他們有新報(bào)紙出版,就會(huì)給你送來。只要你是他們的訂戶,你就會(huì)一直收到新報(bào)紙。 當(dāng)你不

    2024年01月24日
    瀏覽(23)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包