Rust語言之GoF設計模式:中介者Mediator模式
中介者Mediator模式在Rust在實現很難,因為其他語言中的典型 Mediator 實現是 Rust 中的經典反模式:許多物件相互持有可變的交叉引用,試圖相互變異,這在 Rust 中是一個致命的罪過——編譯器不會透過你的第一個天真實施,除非它過於簡單化。
根據定義,Mediator限制了物件之間的直接通訊,並強制它們僅透過 mediator 物件進行協作。它也代表 MVC 模式中的控制器。
有一篇關於Rust 中的中介者模式的研究和討論: https ://github.com/fadeevab/mediator-pattern-rust 。
交叉引用Rc<RefCell<..>>
不推薦這種方法,欺騙 Rust 編譯器。
問題:
- 所有 trait 方法都是隻讀的:不可變self和不可變引數。
- Rc,RefCell在底層被廣泛使用,負責從編譯器到執行時的可變借用。無效的實現會導致執行時的恐慌。
自上而下的所有權
自上而下的所有權方法允許在 Rust 中應用 Mediator,因為它適用於具有嚴格借用檢查器規則的 Rust 所有權模型。雖然不是實現 Mediator 的唯一方法,但它是一種基本比較好的方法。
關鍵是從所有權的角度思考:
1、中介者擁有所有元件的所有權。
2、元件不保留對中介者的引用。相反,它透過方法呼叫獲取其引用。
// A train gets a mediator object by reference. pub trait Train { fn name(&self) -> &String; fn arrive(&mut self, mediator: &mut dyn Mediator); fn depart(&mut self, mediator: &mut dyn Mediator); } // Mediator有提醒通知方法 has notification methods. pub trait Mediator { fn notify_about_arrival(&mut self, train_name: &str) -> bool; fn notify_about_departure(&mut self, train_name: &str); } |
3、控制流從main.rs的fn main()中介接收外部事件/命令的地方開始。
let train1 = PassengerTrain::new("Train 1"); let train2 = FreightTrain::new("Train 2"); // Station車站有`accept`和`depart`方法。 // 但是它也實現了`Mediator'。 let mut station = TrainStation::default(); // Station車站正在接受列車的所有權。 station.accept(train1); station.accept(train2); / `train1`和`train2`已經被移到裡面。 // 但我們可以用train的名字來 depart它們 station.depart("Train 1"); station.depart("Train 2"); station.depart("Train 3"); |
4、Mediator元件之間互動的trait方法是如notify_about_arrival, notify_about_departure通知提醒,這些動作與它用於接收外部事件的外部 API 是不同的(accept,depart是來自主迴圈的命令)。
車站Station的程式碼比較複雜:train_station.rs
下面是元件互動的動作notify_about_arrival, notify_about_departure:
#[derive(Default)] pub struct TrainStation { trains: HashMap<String, Box<dyn Train>>, train_queue: VecDeque<String>, train_on_platform: Option<String>, } impl Mediator for TrainStation { fn notify_about_arrival(&mut self, train_name: &str) -> bool { if self.train_on_platform.is_some() { self.train_queue.push_back(train_name.into()); false } else { self.train_on_platform.replace(train_name.into()); true } } fn notify_about_departure(&mut self, train_name: &str) { if Some(train_name.into()) == self.train_on_platform { self.train_on_platform = None; if let Some(next_train_name) = self.train_queue.pop_front() { let mut next_train = self.trains.remove(&next_train_name).unwrap(); next_train.arrive(self); self.trains.insert(next_train_name.clone(), next_train); self.train_on_platform = Some(next_train_name); } } } } |
同時再實現Train元件介面trait的方法:
impl TrainStation { pub fn accept(&mut self, mut train: impl Train + 'static) { if self.trains.contains_key(train.name()) { println!("{} has already arrived", train.name()); return; } train.arrive(self); self.trains.insert(train.name().clone(), Box::new(train)); } pub fn depart(&mut self, name: &'static str) { let train = self.trains.remove(name); if let Some(mut train) = train { train.depart(self); } else { println!("'{}' is not on the station!", name); } } } |
相關文章
- Rust語言之GoF設計模式: 模板方法模式RustGo設計模式
- Rust語言之GoF設計模式:原型模式RustGo設計模式原型
- Rust語言之GoF設計模式:迭代器模式RustGo設計模式
- Rust語言之GoF設計模式:工廠模式RustGo設計模式
- Rust語言之GoF設計模式:責任鏈模式RustGo設計模式
- Rust語言之GoF設計模式:抽象工廠模式RustGo設計模式抽象
- Rust語言之GoF設計模式:Flyweight享元模式RustGo設計模式
- Rust語言之GoF設計模式:備忘錄Memento模式RustGo設計模式
- Rust語言之GoF設計模式:靜態工廠RustGo設計模式
- Rust語言之GoF設計模式: 直譯器Interpreter模式RustGo設計模式
- Rust語言之GoF設計模式:介面卡AdapterRustGo設計模式APT
- 設計模式--中介者模式Mediator(行為型)設計模式
- JAVA設計模式之 中介者模式【Mediator Pattern】Java設計模式
- 設計模式的征途—22.中介者(Mediator)模式設計模式
- 中介者模式(Mediator Pattern)。模式
- Objective-C設計模式——中介者Mediator(物件去耦)Object設計模式物件
- 設計模式之Mediator(中介者)這樣理解 對嗎?設計模式
- 設計模式之中介者模式設計模式
- 設計模式(十四)中介者模式設計模式
- 設計模式(十一):中介者模式設計模式
- 設計模式_GoF設計模式Go
- GOF設計模式Go設計模式
- 設計模式實戰 - 中介者模式設計模式
- 極簡設計模式-中介者模式設計模式
- 設計模式系列之「中介者模式」設計模式
- Python設計模式-中介者模式Python設計模式
- 設計模式系列之中介者模式(Mediator Pattern)——協調多個物件之間的互動設計模式物件
- 設計模式-行為型模式-中介者模式設計模式
- 設計模式之中介者設計模式
- 設計模式(十七)中介者設計模式
- C#設計模式(16)——中介者模式C#設計模式
- 設計模式學習(十八)中介者模式設計模式
- 我的Java設計模式-中介者模式Java設計模式
- 設計模式系列3--中介者模式設計模式
- C#設計模式之中介者模式C#設計模式
- 23種設計模式之中介者模式設計模式
- Java學設計模式之中介者模式Java設計模式
- 實踐GoF的23種設計模式:裝飾者模式Go設計模式