【问题标题】:Java Builder pattern with inheritance具有继承的 Java Builder 模式
【发布时间】:2018-02-06 02:45:26
【问题描述】:

我想用静态内部类实现一个构建器模式,比如类 A 带有字段 (a1, a2, a3),B 带有字段 (b1, b2) 和 C 带有字段 (c1),而所有共享字段 ( s1, s2) 来自超类 SuperClass:

public class A extends SuperClass {
    private final String a1;
    ...

    private A(ABuilder builder) {
        super(builder);
        this.a1 = builder.a1;
        ...
    }

    public static class ABuilder extends SuperClassBuilder implements ABuilderInterface {
        private String a1;
        ...

        @Override
        public ABuilder withA1(String a1) {
            this.a1 = a1;
            return this;
        }
        ...

        @Override
        public SuperClass build() {
            return new A(this);
        }
    }
}

因此,对于 B 和 C,构建器的不同之处在于它们拥有自己的字段并实现自己的接口(BBuilderInterface 和 CBuilderInterface),而这些接口仅定义要实现的方法:

public interface ABuilderInterface extends SuperClassBuilderInterface {
    ABuilderInterface withA1(String a1);
    ...
}
...<interfaces for B and C>

public interface SuperClassBuilderInterface {
   SuperClassBuilderInterface withS1(String s1);
   ...
   SuperClass build();
}

// Usage of the builders:
public SuperClass foo() {
    return new A.ABuilder()
        .withA1(...) // returns ABuilderInterface
        ...
        .withS1(...) // returns SuperClassBuilderInterface
        ...
        .build();
}

public abstract class SuperClass {
private final String s1;
...

protected SuperClass(SuperClassBuilder builder) {
    this.s1 = builder.s1;
    ...
}

protected static abstract class SuperClassBuilder implements SuperClassBuilderInterface {
    private String s1;
    ...

    @Override
    public SuperClassBuilder withS1(String s1) {
        this.s1 = s1;
        return this;
    }
    ...

    @Override
    public abstract SuperClass build();
}
}

现在你可以发现我在使用builder时必须注意先调用与子类相关的with...方法,然后将它们链接到超类的限制,这不是什么大问题一个交易,但仍不确定是否是好的做法。 另一方面,我可以将子类的 with... 方法一起添加到超类接口中,然后限制就消失了,但是我有一个混合了不同子类的 with... 方法的接口。

你更喜欢/建议哪一个?

【问题讨论】:

  • withS1()ABuilder 中返回什么?
  • @alayor 在 ABuilder 中没有 withS1() 因为它使用的是父级。这个想法是 A、B、C 构建器仅包含其特定的 with... 方法,而共享的方法保留在超级构建器中
  • 这是一个很常见的问题。一种模式是在超类上定义一个通用的“自我类型”,并通过其方法返回。
  • 不清楚你的意思@shmosel
  • 类似thisthis?

标签: java inheritance design-patterns builder


【解决方案1】:

修改超类的构建器以使用 F-bound(又名奇怪的重复模板模式)。

public interface SuperClassBuilderInterface<SELF extends SuperClassBuilderInterface<SELF>> {
    SELF withS1(String s1);
    // etc.
    Superclass build();
}

那么你有:

class SuperClassBuilder<SELF extends SuperClassBuilder<SELF>> implements SuperClassBuilderInterface<SELF>

interface ABuilderInterface<SELF extends ABuilderInterface<SELF>> extends SuperClassBuilderInterface<SELF>

class ABuilder extends SuperClassBuilder<ABuilder> implements ABuilderInterface<ABuilder>

注意SuperClassBuilder 的实现必须包含return (SELF)this; 形式的未经检查的强制转换。类型系统理论上足够强大,不需要它,但生成的编码可能会非常难看(参见this),而且可能不值得。

编辑:这就是@shmosel 的意思

【讨论】:

  • 我刚试了一下,效果很好,非常感谢。首先我不喜欢它,因为它添加了这么多泛型,乍一看我不明白它们是如何工作的,需要三思而后行:) 但对于调用者来说更容易,因为他不会有任何限制
  • 顺便说一句。这是正确的吗?:SuperClassBuilder 的实现将 SELF 作为您提到的return (SELF) this; 返回,ABuilderInterface 的方法返回 SELF,其实现返回 ABuilder
  • 是的。不过,我实际上会编辑答案以不使用未经检查的演员表。
  • 哎呀,这不可能。几乎有可能,但不是真的。
猜你喜欢
  • 1970-01-01
  • 2019-11-23
  • 2013-06-14
  • 1970-01-01
  • 1970-01-01
  • 2013-07-07
  • 2018-07-27
  • 2011-09-12
  • 2013-04-28
相关资源
最近更新 更多