我想实现一种设计模式,在其中设置一个基础构建器类(BaseBuilder.java),其他几个构建器类扩展该类。
基本构建器类是抽象的,它包含其他构建器通用的值。每个构建器都有一些共同的元素,也有独特的元素。
BaseBuilder 类示例-
public class BaseBuilder {
private final String key;
private final String token;
public BaseBuilder(Builder<?> builder) {
this.key = builder.key;
this.token = builder.token;
}
@Override
public String toString() {
return "Builder {" +
", key='" + key + '\'' +
", token='" + token + '\'' +
'}';
}
public abstract static class Builder<T extends Builder <T>> {
private String key;
private String token;
public Builder setKey(String key) {
this.key = key;
return this;
}
public Builder setToken(String token) {
this.token = token;
return this;
}
public BaseBuilder build() {
return new BaseBuilder(this);
}
}
}
现在,我想为其他构建器扩展此 BaseBuilder,例如红车.
public class RedCar extends BaseBuilder {
private final String redWheelCaps;
public RedCar(RedCardBuilder builder) {
super(builder);
this.redWheelCaps = builder.redWheelCaps;
}
@Override
public String toString() {
return "Red Car Builder {" +
", redWheelCaps='" + redWheelCaps + '\'' +
'}';
}
public static class RedCardBuilder extends BaseBuilder<RedCardBuilder> {
private String redWheelCaps;
public RedCardBuilder setRedWheelCaps(String redWheelCaps) {
this.redWheelCaps = redWheelCaps;
return this;
}
public RedCar build() {
return new RedCar(this);
}
}
}
当尝试使用此构建器时,我在尝试实现以下结果时遇到问题。
// this is ideally what I want to achieve
// there is an error because I am not creating a BaseBuilder object
RedCar redCar = new RedCar.RedCarBuilder()
.setKey("key")
.setToken("token")
.setRedWheelCaps("redCaps")
.build();
以上方法不起作用。系统提示我必须使用 BaseBuilder。所以我将代码更新为以下内容:
// this works good, but the order of my set values causes an error
BaseBuilder redCar = new RedCar.RedCarBuilder()
.setKey("key")
.setToken("token")
.setRedWheelCaps("redCaps")
.build();
我被迫使用多态性。这很好,但是,在重新安排设置值的方式之前,我仍然遇到错误。由于某种原因,我必须先设置 RedCar 的值,然后才能设置 BaseBuilder 的值。否则我会收到错误“无法解析方法”。所以我重新排列了我的设置值以消除所有错误。
// no errors at all. This works fine but is not what I was expecting
BaseBuilder redCar = new RedCar.RedCarBuilder()
.setRedWheelCaps("redCaps")
.setKey("key")
.setToken("token")
.build();
如何修复我的设置,以便我可以继承和设置值而不必遵守特定的顺序?无论如何,是否可以在不使用多态性的情况下完成我想要做的事情?我有正确的模式想法吗?谢谢!
编辑: 更多信息是,我可以实现我所寻求的目标,以至于我省略了 BaseBuilder 中的设置器。所以,下面的就OK了。
RedCar redCar = new RedCar.RedCarBuilder()
.setRedWheelCaps("redCaps")
.build();
为什么我似乎无法从 BaseBuilder 继承 setter?
我发现完成您想要的操作的最简洁方法是参数化目标类型和构建器类型。然后,我为类型层次结构的每个级别创建三个构建器类型:接口、抽象类和最终类。听起来工作量很大?欢迎来到 Java 泛型。
我使用 Lombok 注释来减少额外的输入量。这是您的基类及其构建器:
@Getter
public class Rabbit {
private final String sex;
private final String name;
public static Builder<?,?> builder() {
return new BuilderImpl();
}
protected Rabbit(String sex, String name) {
this.sex = sex;
this.name = name;
}
public interface Builder<T extends Rabbit, B extends Builder<T,B>> {
B sex(String value);
B name(String value);
T build();
}
@Getter(AccessLevel.PROTECTED)
protected static abstract class BaseBuilder<T extends Rabbit, B extends BaseBuilder<T,B>>
implements Builder<T,B> {
protected String sex;
protected String name;
@SuppressWarnings("unchecked")
public B sex(String sex)
{
this.sex = sex;
return (B) this;
}
@SuppressWarnings("unchecked")
public B name(String name)
{
this.name = name;
return (B) this;
}
}
private static final class BuilderImpl
extends BaseBuilder<Rabbit,BuilderImpl> {
public Rabbit build()
{
return new Rabbit(getSex(), getName());
}
}
}
这是您的扩展类及其构建者:
@Getter
public class Lop extends Rabbit {
private final float earLength;
private final String furColor;
public static Builder<?,?> builder() {
return new BuilderImpl();
}
protected Lop(String sex, String name, float earLength, String furColor) {
super(sex, name);
this.earLength = earLength;
this.furColor = furColor;
}
public interface Builder<T extends Lop, B extends Builder<T,B>>
extends Rabbit.Builder<T,B> {
public B earLength(float value);
public B furColor(String value);
}
@Getter(AccessLevel.PROTECTED)
protected static abstract class BaseBuilder<T extends Lop, B extends BaseBuilder<T,B>>
extends Rabbit.BaseBuilder<T,B>
implements Builder<T,B> {
private float earLength;
private String furColor;
@SuppressWarnings("unchecked")
public B earLength(float value) {
this.earLength = value;
return (B) this;
}
@SuppressWarnings("unchecked")
public B furColor(String value) {
this.furColor = value;
return (B) this;
}
}
private static final class BuilderImpl
extends BaseBuilder<Lop,BuilderImpl> {
public Lop build()
{
return new Lop(getSex(), getName(), getEarLength(), getFurColor());
}
}
}
测试证实一切正常:
public class RabbitTest {
@Test
public void rabbitTest() {
Lop herman = Lop.builder().furColor("Gray").name("Herman").sex("male").earLength(4.6f).build();
Assert.assertEquals("Herman", herman.getName());
}
}