在 Rust 中實現依賴注入
依賴注入簡單地說,就是類應該依賴於抽象,例如數據源的抽象,而不是具體的實現。這意味着類將依賴於接口而不是真正的類。
這有幾個好處:
1,在不更改客戶端代碼的情況下,很容易將一個實現轉換爲另一個實現。
2,由於接口通常只覆蓋類的總 API 的一小部分,因此可以精確地確定哪個類可以訪問哪些方法和功能。
例如,如果有一個數據源類,可以有一個讀接口和一個寫接口,也可以有兩個接口的組合。然後,每個客戶端可以根據需要擁有其中的任意一個接口,這是最小特權原則的一個例子。
它看起來像這樣:
該模式的總結是:應該依賴於接口,而不是具體的實現,這使得交換相同功能的不同實現變得更加容易。
下面在 Rust 中實現這個模式:
在這個例子中,將建立一個虛構的汽車工廠,它只需要輪子:大輪子和小輪子。由於生產這種輪子的機器具有相同的界面或特性,我們可以使用它:
trait WheelProducer {
fn produce_wheel(&self) -> String;
}
然後,定義一個 CarFactory 結構體,它擁有一個 WheelProducer 的實例:
struct CarFactory {
wheel_producer: Box<dyn WheelProducer>
}
impl CarFactory {
fn change_wheel_producer(&mut self, wheel_producer: Box<dyn WheelProducer>) {
self.wheel_producer = wheel_producer;
}
}
因爲 WheelProducer 是一個 trait 對象,所以我們必須使用 dyn 關鍵字。此外,由於事先不知道生產者的大小,我們必須把它放在一個 Box 裏。
現在來看看我們的第一個 WheelProducer:
struct SmallWheelProducer;
impl WheelProducer for SmallWheelProducer {
fn produce_wheel(&self) -> String {
"Small wheel".to_string()
}
}
SmallWheelProducer 實現了 WheelProducer 接口。接下來我們對 BigWheelProducer 做同樣的事情:
struct BigWheelProducer;
impl WheelProducer for BigWheelProducer {
fn produce_wheel(&self) -> String {
"Big wheel".to_string()
}
}
現在可以測試我們的設置:
fn main() {
let small_wheel_producer = SmallWheelProducer;
let mut factory = CarFactory {
wheel_producer: Box::new(small_wheel_producer)
};
// 生產大輪子的代碼與生產小輪子的代碼一致
let wheel = factory.wheel_producer.produce_wheel();
println!("Wheel produced: {}",wheel);
let big_wheel_producer = Box::new(BigWheelProducer);
factory.change_wheel_producer(big_wheel_producer);
// 生產大輪子的代碼與生產小輪子的代碼一致
let wheel = factory.wheel_producer.produce_wheel();
println!("Wheel produced: {}",wheel);
}
在我們的簡單示例中,手動執行此操作非常容易,然而,在更高級的示例中,它可能變得容易出錯且麻煩。下面的 lib 庫爲我們實現了依賴注入和控制反轉。
實現依賴注入的 crate:
Inject:實現了用於依賴性解析的宏,體現了控制反轉 (IoC) 原則。
Syrette:方便的 Rust 依賴注入和控制反轉框架。
實現這種模式並不十分困難,需要記住的主要事情是面向接口編程而不是具體的實現。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/h7Wn_Sb-ioPaa1r597L6nQ