java - 如何定义构建器模式层次结构,其中可以按任何顺序调用 setter

标签 java generics abstract-class builder

考虑带有抽象生成器的抽象数据类:

abstract class Data {

    abstract static class Builder<T extends Data> {

        private String one;

        protected Builder() {
            this.one = null;
        }

        public final Builder<T> withOne(final String value) {
            this.one = value;
            return this;
        }

        protected abstract T build();
    }

    private final String one;

    protected Data(final Builder<? extends Data> builder) {
        this.one = builder.one;
    }

    public final String getOne() {
        return this.one;
    }
}

该类被扩展,其中还包括自己的扩展Builder:

public final class Extension extends Data {

    public static final class ExtensionBuilder extends Data.Builder<Extension> {

        private String two;

        private ExtensionBuilder() {
            super();
            this.two = null;
        }

        public static final ExtensionBuilder newInstance() {
            return new ExtensionBuilder();
        }

        public final ExtensionBuilder withTwo(final String value) {
            this.two = value;
            return this;
        }

        public final Extension build() {
            return new Extension(this);
        }
    }

    private final String two;

    private Extension(final ExtensionBuilder builder) {
        super(builder);
        this.two = builder.two;
    }

    public final String getTwo() {
        return this.two;
    }
}

Extension 对象从两个类中获取所有方法。但是调用 setter 方法的顺序很重要。这没关系:

Extension one = Extension.ExtensionBuilder
                .newInstance()
                .withTwo("two")
                .withOne("one")
                .build();

而这会产生编译错误:

Extension two = Extension.ExtensionBuilder
                .newInstance()
                .withOne("one")
                .withTwo("two")
                .build();

我知道为什么,withOne() setter 将 Builder 对象的类型从具体类向下转换为抽象类。我想知道我需要做什么来解决这个问题,以便可以按任何顺序调用 setter。

最佳答案

如果您不想(或不能)按照 this answer 中的建议重写 ExtensionBuilder 类中的 withOne 方法, 你可以使用 recursively bounded generic type对于您的 build 者:

abstract static class Builder<T extends Data, B extends Builder<T, B>> {

    private String one;

    protected Builder() {
        this.one = null;
    }

    public final B withOne(final String value) {
        this.one = value;
        return (B) this;
    }

    protected abstract T build();
}

然后,声明ExtensionBuilder类如下:

public static final class ExtensionBuilder 
    extends Data.Builder<Extension, ExtensionBuilder>

这将允许您以任何顺序使用最具体的构建器方法,因为编译器现在知 Prop 体构建器的静态类型。

编辑: 正如 @Radiodef in the comments 指出的那样,还有一个替代方法,它包括在 Builder 类中声明一个 protected abstract B getThis() 方法:

abstract static class Builder<T extends Data, B extends Builder<T, B>> {

    private String one;

    protected Builder() {
        this.one = null;
    }

    protected abstract B getThis();

    public final B withOne(final String value) {
        this.one = value;
        return getThis(); // no need to cast now
    }

    protected abstract T build();
}

当然,在 ExtensionBuilder 中,您应该将其实现为:

@Override
protected ExtensionBuilder getThis() { return this; }

这是来源:http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ205

关于java - 如何定义构建器模式层次结构,其中可以按任何顺序调用 setter ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48429730/

相关文章:

java - 从服务器向所有客户端发送消息

java - 泛型/接口(interface)方法不适用

java - 抽象类方法有没有主体?

c++ - 为什么这个没有声明任何纯虚成员函数的类是抽象的呢?

java - 为什么 javac 有时会创建不必要的变量副本?

java - 如何知道我的java编译器的路径

java - Realm 中的@LinkingObjects 注解是如何工作的

c# - 将数据表转换为列表<T>

java - 如何在 java 中使用泛型类型的节点创建 get 方法

c++ - 如何从虚函数返回泛型派生类?