2016-08-18 2 views
9

BaseBuilder을 확장하려면 일부 DerivedBuilder이 필요하다고 가정합니다. 기본 빌더는 foo (BaseBuilder을 반환)과 같은 몇 가지 메소드가 있습니다. 파생 된 빌더에는 방법 bar이 있습니다. 메소드 barfoo 메소드 다음에 호출해야합니다. 그것을하기 위해이 같은 DerivedBuilderfoo 메소드를 오버라이드 (override) 할 수 있습니다Java 일반 빌더

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

문제는 BaseBuilderfoo 같은 방법을 많이 가지고 내가 그들의 각 하나를 무시해야한다는 것입니다. 그래서 내가 제네릭을 사용하려고 그렇게하고 싶지 않은 :

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; 
    } 
} 

그러나 문제는 내가 아직 여기 DerivedBuilder입니다

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

에도 T 불구하고 쓸 수 있다는 것입니다. 많은 기능을 오버라이드하지 않기 위해 내가 할 수있는 일은 무엇입니까?

+1

을 제네릭이 approch, 당신이 호출 할 수 있습니다 :'새 DerivedBuilder (). foo(). bar()'. 'foo'를 먼저 실행하고'bar'를 실행합니다. 'BaseBuilder' 메서드를 더 호출하고 마지막으로'DerivedBuilder' 메서드를 호출하기를 원한다면'DerivedBuilder' 메서드를 호출 할 수 없기 때문에 두 번째 시간 메서드가'BaseBuilder' 참조를 반환하기 때문에 불가능합니다. s 방법. –

+0

@ Sandeep.KI 그걸 실행하려했는데 컴파일러가'BaseBuilder'에서'bar'가 정의되지 않았다는 불평을합니다. 왜냐하면'foo(). bar()'컴파일러가'foo '이'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의 정의입니다.

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


희망. 인수 new DerivedBuilder<DerivedBuilder<...what?...>>()을 삭제 타입으로 인스턴스화

class DerivedBuilder<T extends DerivedBuilder>; 

: 그리고

2

대신에 return (T) this;을 캐스팅하는 대신 Class.cast(this)을 작성했습니다.

실현하려면

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

hierarch의 모든 클래스는 실제 최종 하위 클래스를 알 필요가있다, 따라서 나는 기본 클래스에 팩토리 메소드를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 Factory를 가지고 있습니다. 또한,'type' 필드와'type.cast (this)'는 추가적인 컴파일 타임 안전을 제공하지 않고 전체를 복잡하게하기 때문에 무의미합니다. – Clashsoft

+0

@XetraSu는 아마도 그것들의 사용법에 맞는'static class'를 제안했습니다. –

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