Java通用构建器

时间:2016-08-18 10:14:37

标签: java generics builder-pattern

假设我需要一些DerivedBuilder来扩展一些BaseBuilder。基础构建器有一些方法,如foo(返回BaseBuilder)。派生构建器具有方法bar。应在方法bar之后调用方法foo。为了做到这一点,我可以覆盖foo中的DerivedBuilder方法,如下所示:

@Override
public DerivedBuilder foo() {
    super.foo();
    return this;
}

问题是BaseBuilder有很多方法,例如foo,我必须覆盖它们中的每一个。我不想这样做,所以我尝试使用泛型:

public class BaseBuilder<T extends BaseBuilder> {
    ...

    public T foo() {
        ...
        return (T)this;
    }
}

public class DerivedBuilder<T extends DerivedBuilder> extends BaseBuilder<T> {
    public T bar() {
        ...
        return (T)this;
    }
}

但问题是我还是不能写

new DerivedBuilder<DerivedBuilder>()
        .foo()
        .bar()

即使这里的TDerivedBuilder。为了不覆盖很多功能,我该怎么做?

4 个答案:

答案 0 :(得分:6)

您的问题是DerivedBuilder

的定义
class DerivedBuilder<T extends DerivedBuilder>;

然后使用类型擦除的参数new DerivedBuilder<DerivedBuilder<...what?...>>()实例化它。

您需要一个完全定义的派生类型,如下所示:

public class BaseBuilder<T extends BaseBuilder<T>> {
    @SuppressWarnings("unchecked")
    public T foo() {
        return (T)this;
    }
}

public class DerivedBuilder extends BaseBuilder<DerivedBuilder> {
    public DerivedBuilder bar() {
        return this;
    }
}

检查ideone.com

答案 1 :(得分:5)

除了BeyelerStudios's answer之外,如果你想进一步嵌套,你可以使用它:

class Base<T extends Base<?>> {
    public T alpha() { return (T) this; }
    public T bravo() { return (T) this; }
    public T foxtrot() { return (T) this; }
}

class Derived<T extends Derived<?>> extends Base<T> {
    public T charlie() { return (T) this; }
    public T golf() { return (T) this; }
}

class FurtherDerived<T extends FurtherDerived<?>> extends Derived<T> {
    public T delta() { return (T) this; }
    public T hotel() { return (T) this; }
}

class MuchFurtherDerived<T extends MuchFurtherDerived<?>> extends FurtherDerived<T> {
    public T echo() { return (T) this; }
}

public static void main(String[] args) {
    new MuchFurtherDerived<MuchFurtherDerived<?>>()
        .alpha().bravo().charlie().delta().echo().foxtrot().golf().hotel()
        .bravo().golf().delta().delta().delta().hotel().alpha().echo()
        .echo().alpha().hotel().foxtrot();
}

答案 2 :(得分:2)

而不是投射return (T) this;我在这里做了Class.cast(this)

意识到:

BaseBuilder.build(ExtendedBuilder.class).foo().bar().foo().bar();

层次结构中的每个类都需要知道实际的最终子类,因此我选择在基类中创建工厂方法 build

this对实际孩子的演员表也是在基类的最终方法中完成的,提供return me();

class BaseBuilder<B extends BaseBuilder<B>> {

    protected Class<B> type;

    public static <T extends BaseBuilder<T>> T build(Class<T> type) {
        try {
            T b = type.newInstance();
            b.type = type;
            return b;
        } catch (InstantiationException | IllegalAccessException e) {
            throw new IllegalStateException(e);
        }
    }

    protected final B me() {
        return type.cast(this);
    }

    B foo() {
        System.out.println("foo");
        return me();
    }
}

class ExtendedBuilder extends BaseBuilder<ExtendedBuilder> {

    ExtendedBuilder bar() {
        System.out.println("bar");
        return me();
    }
}

答案 3 :(得分:0)

我从你的问题中理解,方法foo()应该在方法bar()之前执行 如果这是正确的,您可以应用模板设计模式 在BaseBuilder中创建一个抽象方法栏 一种新方法说“模板”#39;方法模板将定义序列 - 首先执行foo(),然后执行bar() DerivedBuilder将为方法栏提供实现。

public abstract class BaseBuilder {

    public void foo(){
        System.out.println("foo");
    }

    public abstract void bar();

    public void template(){
        foo();
        bar();
    }
}

public class DerivedBuilder extends BaseBuilder{

    @Override
    public void bar() {
        System.out.println("bar");      
    }

    public static void main(String[] args) {
        BaseBuilder builder = new DerivedBuilder();
        builder.template();
    }
}


希望这会有所帮助。