[英]Is a nested Builder class really necessary as described in Effective Java?
因此,在着名的Effective Java書中,它引入了一個Builder模式 ,您可以在其中使用內部靜態Builder類來實例化一個類。 這本書建議了以下類的設計:
public class Example {
private int a;
private int b;
public static class Builder() {
private int a;
private int b;
public Builder a(int a) {
this.a = a;
return this;
}
public Builder b(int b) {
this.b = b;
return this;
}
public Example build() {
return new Example(this);
}
}
private Example(Builder builder) {
this.a = builder.a;
this.b = builder.b;
}
}
但是我無法理解為什么我們真的需要一個內部的Builder class
? 上面的代碼有字段聲明的重復行(int a,b),如果我們有更多字段,這將變得相對混亂。
為什么不擺脫的Builder
類,並讓Example
類采取對所有set
那名的方法Builder
類?
因此,要實例化Example
,它將成為Example e = new Example().a(3).b.(3);
代替Example e = new Example.Builder.a(3).b(3).build();
注意:本書為具有很長參數列表的類建議了這種模式。
Builder是構建復雜對象的模式。 我不認為你的榜樣很復雜; 實際上,構建器添加了大量不必要的代碼,而不僅僅是使用構造函數參數。
您想要使用構建器的原因有幾個:
構造復雜的不可變對象。 不可變對象需要具有最終(或邏輯上最終)字段,因此必須在構造時設置它們。
假設您有N個字段,但您只想在某些用例中明確設置其中的一些字段。 您需要最多2 ^ N個構造函數來覆蓋所有情況 - 稱為“telescoping”,因為參數列表的長度變得越來越長。 構建器允許您為可選參數建模:如果您不想設置該參數,請不要調用該setter方法。
允許自我記錄參數的含義。 通過適當地命名setter方法,您可以一目了然地看到值的含義。
它還有助於驗證您是否意外地反轉了相同類型的參數,因為您可以看到每個值的用途。
如果外部類中的字段是final,那么如果要逐步指定參數值,則必須使用構建器,因為必須在構造函數中初始化所有字段。
構建器內部類允許以遞增方式初始化字段。
正如其他人所指出的那樣,這也適用於不可變對象。 這些領域不一定是最終的; 如果在外層沒有提供制定者,它們將是有效的。
構建器可以比直接構造更有效地累積參數。 考慮一下StringBuilder
。 它分配一個臨時緩沖區來累積部分結果。 其案例中的“構建”操作是toString()
。
最后,可能有一些你在類的構造函數中無法做到的事情。 如果您需要將值傳遞給超級構造函數,但該值不是構造函數的參數的一部分,則可能無法,因為您必須首先調用super()
,並且您可能無法創建argument(s)作為super(...)
調用中的一個簡單表達式。 想到BoxLayout。 您將JPanel
傳遞給BoxLayout
構造函數。 您將布局傳遞給JPanel
構造函數。 雞肉和雞蛋。 而這種代碼是不允許的,因為this
尚未構成。
class X extends JPanel {
X() {
super( new BoxLayout(this) ); // Error: Cannot use "this" yet
}
}
幸運的是, JPanel
不是一成不變的; 你可以在施工后設置布局。
理由是復雜的課程。 請注意, Builder
對象返回自身,因此可以進行鏈接,例如:
Example exp = Example.Builder().a(5).b(10).build();
在某些情況下,Apache使用此方法來允許增量設置各種值。 它還允許.build()
方法對所有正確的值進行一些檢查,以便在需要時創建對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.