Rust 精簡構造器
在這篇短文中,我們將介紹構造器模式的表親 -- 精簡構造器。
不像傳統的構造器,需要一個單獨的構造器對象,精簡構造器重用對象本身來提供構造器的功能。
我們來看一個例子:
精簡構造器
pub struct Shape {
position: Vec3,
geometry: Geometry,
material: Option<Material>,
}
impl Shape {
pub fn new(geometry: Geometry) -> Shape {
Shape {
position: Vec3::default(),
geometry,
material: None,
}
}
pub fn with_position(mut self, position: Vec3) -> Shape {
self.position = position;
self
}
pub fn with_material(mut self, material: Material) -> Shape {
self.material = Some(material);
self
}
}
// Call site
let shape = Shape::new(Geometry::Sphere::with_radius(1))
.with_position(Vec3(0, 9, 2))
.with_material(Material::SolidColor(Color::Red));
完整構造器
相比之下,完整構造器在定義上明顯更加冗長,且需要兩次額外的調用,如下:
pub struct Shape {
position: Vec3,
geometry: Geometry,
material: Option<Material>,
}
pub struct ShapeBuilder {
position: Option<Vec3>,
geometry: Option<Geometry>,
texture: Option<Texture>,
}
impl Shape {
pub fn builder() -> ShapeBuilder { ... }
}
impl ShapeBuilder {
pub fn position(&mut self, position: Vec3) -> &mut Self { ... }
pub fn geometry(&mut self, geometry: Geometry) -> &mut Self { ... }
pub fn material(&mut self, material: Material) -> &mut Self { ... }
pub fn build(&self) -> Shape { ... }
}
// Call site
let shape = Shape::builder()
.position(Vec3(9, 2))
.geometry(Geometry::Sphere::with_radius(1))
.material(Material::SolidColor(Color::Red))
.build();
精簡構造器最主要的好處就是它可以增量的、零成本的方式構建對象。因此,在代碼以不確定的方向快速發展的情況下,它特別有用。在工作中,找到了一個實際的例子,如下:
impl PeerManagerActor {
pub fn new(
store: Store,
config: NetworkConfig,
client_addr: Recipient<NetworkClientMessages>,
view_client_addr: Recipient<NetworkViewClientMessages>,
routing_table_addr: Addr<RoutingTableActor>,
) -> anyhow::Result<Self> {
這裏有一個 new 方法,及一大堆各種依賴的參數。我們需要做的是,還要增加另外的依賴,爲了能在測試中被重寫。首先嚐試的是,在 new 方法中加入新的參數,如下:
pub fn new(
store: Store,
config: NetworkConfig,
client_addr: Recipient<NetworkClientMessages>,
view_client_addr: Recipient<NetworkViewClientMessages>,
routing_table_addr: Addr<RoutingTableActor>,
+ ping_counter: Box<dyn PingCounter>,
) -> anyhow::Result<Self> {
然而這種方式,我們需要修改 7 處調用 new 方法的地方。替換成精簡構造器模式,我們就只需要修改一處,也就是我們關心的 counter 部分。
命名注意事項
如果構造器的方法恰巧被使用了,with_foo 是最好的命名方式。對於布爾類型,有時需要同時寫 2 個構造器方法,如下:
pub fn fancy(mut self) -> Self {
self.with_fancy(true)
}
pub fn with_fancy(mut self, yes: bool) -> Self {
self.fancy = yes;
self
}
本文翻譯自:
https://matklad.github.io/2022/05/29/builder-lite.html
coding 到燈火闌珊 專注於技術分享,包括 Rust、Golang、分佈式架構、雲原生等。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/g1Yg4XFBDBtIPnYf1eC97Q