簡體   English   中英

Builder模式與配置對象

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM