2016-08-18 17 views
9

假设我需要一些DerivedBuilder来扩展一些BaseBuilder。基本构建器有一些方法,如foo(它返回BaseBuilder)。派生建筑师有方法bar。应在方法foo后调用方法bar。为了做到这一点,我可以在DerivedBuilder像这样覆盖foo方法:Java通用构建器

@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() 

即使T这里是DerivedBuilder。我可以做什么以避免覆盖很多功能?

+1

有了这个计算策略仿制药,你可以拨打:'新DerivedBuilder ()。 FOO()。栏()'。它将首先工作并执行'foo',然后执行'bar'。如果你想调用更多的'BaseBuilder'方法,最后你想调用'DerivedBuilder'方法,那么这是不可能的,因为第二次,方法返回'BaseBuilder'的引用,你不能调用'DerivedBuilder' s方法。 –

+0

@ Sandeep.KI试图执行该操作,编译器抱怨''Bar'没有在'BaseBuilder'中定义,因为那时我执行'.foo().bar()'编译器在执行'foo之后唯一知道'T'的东西'是这个'T'扩展了'BaseBuilder' – PepeHands

+0

请参见[this](http://stackoverflow.com/questions/4217013/how-to-force-derived-class-to-call-super-method-like-android -does)和[this](http://stackoverflow.com/questions/6853638/require-override-of-method-to-call-super)和[this](http://stackoverflow.com/questions/6142460/how-do-i-force-a-polymorphic-call-to-the-super-method)... – user1803551

回答

5

你的问题是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

+0

是否还有可能进一步派生'DerivedBuilder',例如'SubDerivedBuilder'? 'SubDerivedBuilderM <...> extends DerivedBuilder <...>' –

+1

@MCEmperor是的,但是你需要让所有派生类型都通过完整的类型到它们的基类。检查[this fork](http://ideone.com/ZIAuqs) – BeyelerStudios

0

我的理解是你的问题是foo()方法应该在方法bar()之前执行。
如果这是正确的,您可以应用模板设计模式。
在BaseBuilder中创建一个抽象方法栏。
而一种新的方法说'模板'。方法模板将定义序列 - 首先执行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(); 
    } 
} 


希望这有助于。

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(); 
    } 
} 
+0

现在你有一个Builder工厂。此外,'type'字段和'type.cast(this)'是没有意义的,因为它不提供任何额外的编译时安全性并且使整个事情复杂化。 – Clashsoft

+0

@XetraSu建议'静态类'这可能适合他们的用法。 –

4

除了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(); 
}