【发布时间】:2019-12-19 04:53:41
【问题描述】:
我有一个包含一个抽象基类和几个子类的类层次结构。基类有大约 25 个字段,每个子类有一个额外的 0-8 个字段。
我想使用 Builder 模式来构造每个子实例,并且我想尽可能地使用 Lombok 来保持代码简洁。在this suggestion 之后,我的代码如下:
@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 本身会使类变得非常可变。-
还有其他关于构建器/继承的问题
- Builder Pattern and Inheritance
- Subclassing a Java Builder class
- how to Call super constructor in Lombok
但是,他们都没有谈论让每个孩子都有一个“基础建设者” builder 是一个子类。所以,我无法弄清楚使用泛型,
setBValues函数的第二个参数应该是什么。 - 我还尝试了 Lombok 的
@Superbuilder注释,但同样,虽然它大大简化了代码,但我仍然不知道如何获得基础构建器。
【问题讨论】:
-
如果你使用
@SuperBuilder,你不能简单地创建一个方法(可能在你的BValuesProvider类中)以抽象BaseBuilder作为参数,并在其中调用builder的setter吗? -
不确定我是否理解如何做到这一点 - 你能给我看一个小例子吗?另外,我应该提到
BValuesProvider不是我必须修改的类,因为它属于不同的包。我想我可以为此添加另一个接口类(?)。