[英]Builder pattern vs. config object
構建器模式在創建不可變對象時很流行,但是創建構建器會產生一些編程開銷。 所以我想知道為什么不簡單地使用配置對象。
構建器的用法如下所示:
Product p = Product.Builder.name("Vodka").alcohol(0.38).size(0.7).price(17.99).build();
很明顯,這是非常易讀和簡潔的,但您必須實現構建器:
public class Product {
public final String name;
public final float alcohol;
public final float size;
public final float price;
private Product(Builder builder) {
this.name = builder.name;
this.alcohol = builder.alcohol;
this.size = builder.size;
this.price = builder.price;
}
public static class Builder {
private String name;
private float alcohol;
private float size;
private float price;
// mandatory
public static Builder name(String name) {
Builder b = new Builder();
b.name = name;
return b;
}
public Builder alcohol(float alcohol) {
this.alcohol = alcohol;
return.this;
}
public Builder size(float size) {
this.size = size;
return.this;
}
public Builder price(float price) {
this.price = price;
return.this;
}
public Product build() {
return new Product(this);
}
}
}
我的想法是,通過使用這樣的簡單配置對象來減少代碼:
class ProductConfig {
public String name;
public float alcohol;
public float size;
public float price;
// name is still mandatory
public ProductConfig(String name) {
this.name = name;
}
}
public class Product {
public final String name;
public final float alcohol;
public final float size;
public final float price;
public Product(ProductConfig config) {
this.name = config.name;
this.alcohol = config.alcohol;
this.size = config.size;
this.price = config.price;
}
}
用法:
ProductConfig config = new ProductConfig("Vodka");
config.alcohol = 0.38;
config.size = 0.7;
config.price = 17.99;
Product p = new Product(config);
這種用法需要更多行,但也非常易讀,但實現起來要簡單得多,也許對於不熟悉構建器模式的人來說更容易理解。 順便說一下:這個模式有名字嗎?
配置方法有缺點我忽略了嗎?
構建器模式改進了解耦 - 您的Product可以是一個接口,唯一知道實現(或在某些情況下實現)的類是構建器。 如果構建器還實現了接口,那么您可以將其注入代碼中以進一步增加解耦。
這種解耦意味着您的代碼更易於維護且更易於測試。
正如已經指出的那樣,你正在失去構建器模式的幾個優點(與干凈的構建器相比, 新的難看並且難以維護和泄漏細節)。
然而,我最想念的是構建器模式可用於提供所謂的“流暢接口” 。
而不是這個:
ProductConfig config = new ProductConfig("Vodka");
config.alcohol = 0.38;
config.size = 0.7;
config.price = 17.99;
Product p = new Product(config);
你可以做:
ProductFactory.create()
.drink("Vodka")
.whereAlcohoolLevelIs(0.38)
.inABottleSized(0.7)
.pricedAt(17.99)
.build();
並不是每個人都喜歡流暢的界面,但它們絕對是對構建器模式的非常好用(所有流暢的接口都應該使用構建器模式,但並非所有構建器模式都是流暢的接口)。
一些優秀的Java集合,如Google集合,使得“流暢的接口”非常自由和非常好用。 我會在你的“更容易打字/更少字符”的方法中選擇這些:)
你試圖用你的模式解決什么問題? 構建器模式用於具有許多(可選)參數的對象,以防止大量不同的構造函數或非常長的構造函數。 它還可以在構造期間使對象保持一致狀態(與javabean模式相對)。
構建器和“配置對象”(感覺就像一個好名字)之間的區別在於,您仍然需要通過構造函數或getter / setter創建具有相同參數的對象。 這a)不解決構造函數問題或b)使配置對象保持不一致狀態。 配置對象的不一致狀態不會真正傷害它,但您可以將未完成的配置對象作為參數傳遞。 [Michids鏈接到幻像類型似乎解決了這個問題,但這再次殺死了可讀性( new Foo<TRUE,TRUE, TRUE, FALSE, TRUE>
有點糟糕)。]這就是構建器模式的一大優勢:你可以驗證你的params在創建對象之前,您可以返回任何子類型(就像工廠一樣)。
配置對象對於所有必需的參數集都有效。 我曾經在.NET或java中多次看過這種模式。
您是否考慮過使用構建器構建器 ?
我認為構建器(帶有“With”之類的前綴)更自然/流利地讀取。
我個人認為,第一眼看到的構建器模式為您提供了更清晰的代碼,其中實際使用了這些對象。 另一方面,沒有getter / setter將不會被許多期望camel case getter / setter的框架所使用。 我覺得這是一個嚴重的退縮。
我也喜歡getter / setter,你清楚地看到你在做什么:得到或設置。 我覺得這位建築師在這里失去了一點直觀的清晰度。
我知道很多人已經閱讀了一本特定的書,現在突然之間,建設者模式已經享受了炒作,好像它是新的iPhone。 但是,我不是早期采用者。 我只使用“新方式”,它真正證明了在任何領域都能節省大量時間,無論是性能,維護,編碼......
我的實踐經驗是,我通常更喜歡吸氣/安裝和施工人員。 它允許我將這些POJO用於任何目的。
雖然我看到了Config對象的用途,但我也認為它比構建器更具開銷,為什么呢? 安裝者有什么問題?
也許我們需要發明一個WITH子句:例如,假設你有
public Class FooBar() {
private String foo;
public void setFoo(String bar) {
this.foo = bar;
}
public String getFoo() {
return this.foo;
}
}
public static void main(String []args) {
FooBar fuBar = new FooBar();
String myBar;
with fuBar {
setFoo("bar");
myBar = getFoo();
}
}
啊我不知道......我認為這可能會導致更快的代碼編寫而沒有內部的所有麻煩。 有沒有人與Oracle Java大師有聯系?
它看起來不像使用構建器的對象那樣干凈,但是您可以節省構建器構建時間。 你仍然可以使用該類作為常規的pojo / bean,可以在框架中使用...
你們真的喜歡這個條款還是你認為它會更糟糕? 干杯
IMO,如果您有驗證等內容,那么構建器模式會更加強大。
您的案例中的構建器模式可以更改為執行以下操作:
Product p = new ProductBuilder("pName").alcohol(0.38).size(0.7).price(17.99).build();
build()
方法可以完成構建器所需的所有驗證工作。 構建器模式還有幾個設計方案(所有這些都可能不適用於您的情況)。 對於deatils,請檢查此問題
配置模式和構建器模式在功能上是等效的。 他們都解決了同樣的問題 -
消除了對多個構造函數簽名的需要
允許僅在構造期間設置字段
允許使用者僅設置他們關心的值,並具有其他值的邏輯默認值
您可以在其中一種模式中執行任何操作,例如,只允許使用執行驗證的方法設置狀態,並使用封裝邏輯設置狀態。 唯一真正的區別是,如果您喜歡使用new
關鍵術語創建對象,或者您喜歡調用.build()
方法。
主要的缺點是它不在約書亞的書中,因此無人機無法繞過它。
你正在使用一個簡單的值對象來保存函數(/ method / constructor)需要的多個參數,沒有任何問題,它已經做了很多年。 只要我們沒有命名可選參數,我們就必須設計這樣的解決方法 - 這是一種恥辱,而不是來自太陽神靈的那些神奇的發明。
真正的區別在於您直接暴露字段。 約書亞永遠不會有一個公共的可變領域 - 但他寫的API將被數百萬人使用,其中大部分是蠢貨,而且API必須安全地發展到未來幾十年,並且他們可以分配許多個月只是為了設計一個簡單的課程
我們是誰來哄騙那個?
您不應使用公共字段,而應使用受保護或私有字段。 對於訪問,你應該使用getters和setter來保持封裝。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.