使用 Lombok 的类层次结构的 Common Builder 基实例

我有一个类层次结构,其中包含一个抽象基类和几个子类。基类有 ~25 个字段,每个子类都有额外的 0-8 个字段。

我想使用 Builder 模式来构造每个子实例,并且我想尽可能使用 Lombok 以保持代码简洁。按照这个建议, 我有如下代码:

@AllArgsConstructor

@Data

public abstract class Base {

   private int b1, b2, ... , b25;

}


public class C1 extends Base {

   private int c11, c12, ... , c16;


   @Builder

   private C1(int b1, int b2, ..., int b25, int c11, ... int c16) {

       super(b1, b2, ...., b25);

       this.c11 = c11;

       ...

       this.c16 = c16;

   }

}


public class C2 extends Base {


   @Builder

   private C2(int b1, int b2, ..., int b25) {

       super(b1, b2, ...., b25);

   }

}

这使得构建子类变得容易


C1 c1 = C1.builder().b1(1).b2(2)....b25(25).c11(101).c12(102).build();

C2 c2 = C2.builder().b1(1).b2(2)....b25(25).build();

问题是.b1().b2()...每次创建任何子类时都会重复链接调用。


理想情况下,我想要一种通用的方法来设置 B 值,而不管正在构建哪个子类。(假设还有另一个类BValuesProvider可以提供这些值)


public void setBValues(BValuesProvider bv, // what else goes here??? //) {

    // something.b1(bv.b1()).b2(bv.b2()) ...

}


public createC1(BValuesProvider bv, c11, c12, ..., c16) {

    C1.Builder c1b = C1.builder().c11(c11).c12(c12)....c16(c16);

    // Call setBValues somehow

    return c1b.build();

}


public createC2(BValuesProvider bv) {

    // Call setBValues somehow

    return c2b.build();

}

我当前的解决方案是将注释附加@Data到基类以公开 setter/getter,因此我的代码如下所示:


public void setBValues(BValuesProvider bv, Base cx) {

    cx.setB1(bv.b1());

    cx.setB2(bv.b2());

    ...

    cx.setB25(bv.b25());

}


public createC1(BValuesProvider bv, c11, c12, ..., c16) {

    C1 c1 = C1.builder().c11(c11).c12(c12)....c16(c16).build();

    setBValues(bv, c1);

    return c1;

}


public createC2(BValuesProvider bv) {

    C2 c2 = C2.builder().build();

    setBValues(bv, c2);

    return c2;

}

问题:

  • 有一个更好的方法吗?具体来说,我觉得首先(完全)构建一个子类,然后setBxx()在其上调用函数似乎是一种糟糕的模式。暴露 setter 本身使类非常可变。

  • SO 上还有其他关于构建器/继承的问题

    但是,他们都没有谈论拥有每个子构建器都是其子类的“基础构建器”。所以,我不知道使用泛型,函数的第二个参数setBValues应该是什么。

    • 建造者模式与继承

    • 继承 Java Builder 类

    • 如何在 Lombok 中调用超级构造函数

  • 我也尝试了 Lombok 的@Superbuilder注解,但同样,虽然它大大简化了代码,但我仍然不知道如何获得基础构建器。


繁星coding
浏览 146回答 2
2回答

ITMISS

@SuperBuilder这可以使用(实验性的)注释和 lombok >= 1.18.4来实现。您可以通过添加一个接受 a作为参数并设置所有值的方法来自定义@SuperBuilderof :BaseBValuesProvider@SuperBuilderpublic abstract class Base {&nbsp; &nbsp; public static abstract class BaseBuilder<C extends Base, B extends BaseBuilder<C, B>> {&nbsp; &nbsp; &nbsp; &nbsp; public B fillFromProvider(BValuesProvider bv) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b1(bv.b1());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b2(bv.b2());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return self();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; ...}然后你可以像这样使用它(实例bv在哪里BValuesProvider):C1 c1 = C1.builder().fillFromProvider(bv).c11(11).build();

喵喵时光机

OP在这里。虽然这不是我提出的确切问题的答案,但我想分享一个仍然使用 Lombok 但不使用 @Builder 的替代方案。@Getterpublic abstract class Base<T extends Base> {&nbsp; &nbsp;private int b1, b2, ... , b25;&nbsp; &nbsp;private T cast() { return (T) this; }&nbsp; &nbsp;public T setB1(final int b1) { this.b1 = b1; return cast(); }&nbsp; &nbsp;public T setB2(final int b2) { this.b2 = b2; return cast(); }&nbsp; &nbsp;...}@Getter @Setter @Accessors(chain = true)public class C1 extends Base<C1> {&nbsp; &nbsp;private int c11, c12, ... , c16;&nbsp; &nbsp;public static C1 init() { return new C1(); }&nbsp; &nbsp;private C1() {}}@Getter @Setter @Accessors(chain = true)public class C2 extends Base<C2> {&nbsp; &nbsp;public static C2 init() { return new C2(); }&nbsp; &nbsp;private C2() {}}我刚刚泛化了基类并在子类上使用了链式访问器。然后调用者将被修改为:public void setBValues(BValuesProvider bv, Base cx) {&nbsp; &nbsp; cx.setB1(bv.b1())&nbsp; &nbsp; &nbsp; .setB2(bv.b2())&nbsp; &nbsp; &nbsp; ...&nbsp; &nbsp; &nbsp; .setB25(bv.b25());}public createC1(BValuesProvider bv, c11, c12, ..., c16) {&nbsp; &nbsp; C1 c1 = C1.init().setC11(c11)....setC16(c16);&nbsp; &nbsp; setBValues(bv, c1);&nbsp; &nbsp; return c1;}public createC2(BValuesProvider bv) {&nbsp; &nbsp; C2 c2 = C2.init();&nbsp; &nbsp; setBValues(bv, c2);&nbsp; &nbsp; return c2;}优点:我的代码不需要知道BValuesProvider以这种链式方式设置公共基本参数对我来说似乎更自然缺点:基类有点冗长,但总的来说,它还不错,因为我们避免了每个子类中的大构造函数。它不是真正的 Builder 模式,因为我们正在创建对象并在其上执行一系列 set() 与在.builder().x(x).y(y).build()其上执行操作。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java