亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用 Builder 也可以構建封裝對象

使用 Builder 也可以構建封裝對象

MYYA 2023-03-02 15:39:53
想象一下,我有一個類封裝了另一個類:@Builderpublic class Dragon {  private Dimensions dimensions;  private String name;  public static class ParentBuilder {    DimensionsBuilder innerBuilder = Dimensions.builder();    public DragonBuilder height(double height) {      this.innerBuilder.height(height);      return this;    }    public DragonBuilder length(double length) {      this.innerBuilder.length(length);      return this;    }    public Dragon build() {      return Dragon.builder()        .dimensions(this.innerBuilder.build())        .name(this.name)        .build();    }  } }@Builderpublic class Dimensions {  private double height;  private double length;}請記住,這是一個非常簡化的示例,真正的代碼(不幸的是,與龍無關)將很多屬性委托給innerBuilder.這樣,我可以像這樣實例化類:Dragon dragon = Dragon.builder()  .height(12.0)  .length(25.0)  .name("Smaug")  .build();而不是這樣:Dragon dragon = Dragon.builder()  .dimensions(Dimensions.builder()    .height(12.0)    .length(25.0)    .build())  .name("Smaug")  .build;添加構建器方法以直接構建內部類也是好的編碼習慣嗎?或者它是否違反了某些設計原則,因為它可能耦合得太緊了?我已經遇到的一個問題是在對內部類進行重構時,我還必須對父類應用大部分相同的重構。
查看完整描述

1 回答

?
慕斯王

TA貢獻1864條經驗 獲得超2個贊

在我看來,從風格/設計的角度來看,您的方法沒有根本性的錯誤。但是,正如用戶 JB Nizet 在評論中所解釋的那樣,存在兩個主要問題:

  1. 您會遇到維護問題,因為您必須復制每個外部構建器方法。(Lombok@Delegate在這里幫不了你,因為它對 Lombok 本身生成的類不起作用。)

  2. 您的構建器的用戶可以同時調用dimensions(Dimensions)委托方法和委托方法,這非常令人困惑。

從用戶的角度來看,我希望這樣使用構建器:

Dragon dragon = Dragon.builder()

    .dimensions()

        .height(12.0)

        .length(25.0)

        .back()

    .name("Smaug")

    .build();

這是實現它的方法(使用 Lombok 1.18.8):


@Builder

public class Dragon {

    private Dimensions dimensions;

    private String name;


    public static class DragonBuilder {


        private Dimensions.DimensionsBuilder innerBuilder = 

                new Dimensions.DimensionsBuilder(this);


        // If a method of the same name exists, Lombok does not generate

        // another one even if the parameters differ.

        // In this way, users cannot set their own dimensions object.

        public Dimensions.DimensionsBuilder dimensions() {

            return innerBuilder;

        }


        // Customize build() so that your innerBuilder is used to create 

        // the Dimensions instance.

        public Dragon build() {

            return new Dragon(innerBuilder.build(), name);

        }

    }

}

的構建器Dimensions持有對容器的引用DragonBuilder:


// Don't let Lombok create a builder() method, so users cannot 

// instantiate builders on their own.

@Builder(builderMethodName = "")

public class Dimensions {

    private double height;

    private double length;


    public static class DimensionsBuilder {

        private Dragon.DragonBuilder parentBuilder;


        // The only constructor takes a reference to the containing builder.

        DimensionsBuilder(Dragon.DragonBuilder parentBuilder) {

            this.parentBuilder = parentBuilder;

        }


        // Provide a method that returns the containing builder.

        public Dragon.DragonBuilder back() {

            return parentBuilder;

        }


        // The build() method should not be called directly, so 

        // we make it package-private.

        Dimensions build() {

            return new Dimensions(height, length);

        }

    }

}

這種方法可以擴展,因為 Lombok 會自動在構建器中生成所有必要的剩余 setter 方法。此外,由于用戶提供了自己的Dimensions實例,因此可能不會出現意外。(你可以允許這樣做,但我強烈建議對潛在的沖突進行運行時檢查,例如檢查是否已調用這兩種方法。)


缺點是它Dimensions.builder()不再可用,因此不能直接使用或在其他具有Dimensions字段的類的構建器中使用。但是,也有一個解決方案:使用@SuperBuilder Dimensions并定義一個class NestedDimensionsBuilder extends Dimensions.DimensionsBuilder<Dimensions, NestedDimensionsBuilder>within DragonBuilder。


查看完整回答
反對 回復 2023-03-02
  • 1 回答
  • 0 關注
  • 158 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號