Rust 中的設計模式:觀察者模式 -Observer-

觀察者模式介紹

觀察者模式是一種軟件設計模式,它允許對象 (通常稱爲主題) 維護一個稱爲觀察者的依賴項列表,並自動通知它們任何狀態更改。

許多語言都有這種模式,要麼是內置的,要麼是在標準庫中。

1,首先是 Observable,它可以是一個接口,被觀察的對象。被觀察對象擁有一個觀察者列表。

2,Observer,觀察者。這也可以是一個接口。

3,ConcreteObservable,保存狀態的具體類。如果狀態中有任何變化,則調用 setState 方法,然後調用 notify 方法反過來通知觀察者。

4,ConcreteObserverA/B,處理狀態變化的具體觀察者。

在 Rust 中實現觀察者模式

新建一個 Rust 項目:

cargo new rust_observer

我們將從 Observer 特徵開始:

trait Observer {
    fn update(&self, data:&str);
}

這很簡單,Observer 只有一個方法 update,它有一些數據作爲參數。

現在實現 Subject:

struct Subject<'a> {
    observers: Vec<&'a dyn Observer>,
    state: String,
}

impl<'a> Subject<'a> {
    fn new(state: String) -> Self {
        Self {
            observers: Vec::new(),
            state: state,
        }
    }

    fn attach(&mut self, observer: &'a dyn Observer) {
        self.observers.push(observer);
    }

    fn detach(&mut self, observer: &dyn Observer) {
        self.observers.retain(|o| !std::ptr::eq(*o, observer));
    }


    fn notify(&self) {
        for o in &self.observers {
            o.update(&self.state);
        }
    }

    fn set_state(&mut self, state: String) {
        self.state = state;
        self.notify();
    }
}

1,在 Subject 結構體中,觀察者必須具有與整個結構體相同的生命週期。

2,new 方法,即構造函數,非常簡單。

3,attach 方法,將觀察者加入列表中。

4,detach 方法,使用指定的閉包進行篩選。閉包返回 true 的每個元素都保留在 vector 中,當它返回 false 時,這些元素被刪除。

5,notify 方法遍歷每個觀察者,並在每個觀察者上調用 update 方法。

6,set_state 方法改變狀態,並調用 notify,以便每個觀察者都能對狀態變化做出反應。

現在建立一個真正的 observer:

struct ConcreteObserver {
    name: String,
}

impl Observer for ConcreteObserver {
    fn update(&self, data:&str) {
        println!("{} received data: {}",self.name,data);
    }
}

測試

fn main() {
    let mut subject = Subject::new("initial data".to_string());

    let observer1=ConcreteObserver {
        name: "Observer 1".to_string(),
    };

    let observer2=ConcreteObserver {
        name: "Observer 2".to_string(),
    };

    subject.attach(&observer1);
    subject.attach(&observer2);

    subject.set_state("updated_data".to_string());

    subject.detach(&observer2);

    subject.set_state("Again updated data".to_string());   

    subject.detach(&observer1);
}

1,我們用一些初始數據實例化 Subject。

2,然後定義兩個觀察者,它們都是 concreteobserver。每一個都有一個不同的名稱。

3,然後我們需要將它們附加到 Subject。

4,set_state 方法被調用,這會將狀態變化發送給兩個觀察者,並將其打印出來。

5,爲了確保 detach 方法正確運行,我們分離第二個觀察者。

6,我們再調用一次 set_state 方法,我們現在應該只得到一條打印語句。

執行 cargo run,結果如下:

Observer 1 received data: updated_data
Observer 2 received data: updated_data
Observer 1 received data: Again updated data

可能的改進

一個可能的改進是使其線程安全,因爲現在這個實現不是線程安全的。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/EsEvWxQo3oi900rx11jvhw