2012-06-10 2 views
17

여러 구현이 Foo이고 여러 개의 숫자가 FooBuilder 인 경우 문제가 발생합니다. Foo은 설정해야하는 몇 가지 공통 변수를 공유하지만 각각의 특정 기능을 구현하려면 각각의 FooBuilder을 필요로하는 고유 변수가 있습니다. 여러 가지 FooBuilder 구현과, 등등Java : 수퍼 클래스 메서드 시그니처의 서브 클래스 반환

public abstract class FooBuilder { 
    ... 

    public FooBuilder setA(int A) { 
    this.A = A; 
    return this; 
    } 

    ... 
} 

public class FooImplBuilder extends FooBuilder{ 
    ... 
    public FooImplBuilder setB(int B) { 
    this.B = B; 
    return this; 
    } 
    public FooImplBuilder setC(int C) { 
    this.C = C; 
    return this; 
    } 
    ... 
} 

그리고 : 간결, 나는 같은 방법 체인을 사용하도록 FooBuilder 's의 세터를하고 싶습니다. 이것은 기술적으로 모든 것을 원하지만,이 접근법은 메서드 체이닝이 수행 될 때 메서드 호출의 순서에 민감합니다.

someFoo.setA(a).setB(b)... 

방법은 체인 호출의 개발자가 순서에 대해 생각하도록 요구 다음이 방법은 컴파일 오류가 정의되지. 이것을 피하기 위해, 나는 어떻게 든 실제 구현 하위 클래스를 반환 FooBuilder에 setters을 가지고 싶습니다. 그러나, 나는 이것을 어떻게하는지 잘 모릅니다. 가장 좋은 방법은 무엇입니까?

+0

또한 모든 곳에서 강제로 캐스팅되거나 원하는 경우 수퍼 클래스의 속성을 변경하지 못하게합니다. –

답변

13

이것은 좋은 질문이며 실제적인 문제입니다.

Jochen의 대답에서 언급 한 것처럼 Java에서이 문제를 처리하는 가장 쉬운 방법은 제네릭을 사용하는 것입니다.

문제의 좋은 토론과 항상 올바른 클래스의 빌더를 반환하는 문제를 해결하기 위해 빌더 서브 클래스에서 오버라이드 (override) getThis() 방법의 정의와 제네릭을 결합 Using Inheritance with Fluent Interfaces에이 블로그 항목에 합리적인 해결책이있다.

+1

나는이 해결책을 좋아한다. 내가 제안한 것보다 훨씬 정교하지만, 더 유연하고 궁극적으로 우아합니다. – Jochen

+0

링크 된 블로그를 요약하고 별도의 빌더를 제거하십시오. public abstract class X > {public int a; public B setA (int foo) {this.a = foo; return getThis();} public abstract B getThis();} public 클래스 Y extends X {public int b; public Y setB (int bar) {this.b = bar; ' –

3

여기에가는 길은 제네릭 일 수 있습니다.

당신은 세타()이 (의사 코드) 같은

<T> T setA(int a) 

당신이 코드에서 힌트를 줄 수없는 경우 컴파일러는 실제 유형을 알아낼 수, 그리고해야를 선언하면 like

obj.<RealFoo>setA(42) 
+3

+1 :이 전략에 대한 설명은 http://egalluzzo.blogspot.com/2010/06/using-inheritance-with-fluent.html –

+0

에서 확인할 수 있습니다. 컴파일러는 연결된 유형을 알아 내지 못합니다 메소드 호출 및 각 메소드 호출에 대한 유형 반복은 거의 옵션이 아닙니다. – meriton

+0

@DonRoby : 답변으로 게시하지 않는 이유는 무엇입니까? 그것은 Jochen 's보다 나은 해결책이되고 upvote ;-) – meriton

1

찾았 으면 this excellent answer 나는 그것을 공유하고 있습니다.

public class SuperClass<I extends SuperClass> 
{ 
    @SuppressWarnings("unchecked") // If you're annoyed by Lint. 
    public I doStuff(Object withThings) 
    { 
     // Do stuff with things. 
     return (I)this ; // Will always cast to the subclass. Causes the Lint warning. 
    } 
} 

public class ImplementationOne 
extends SuperClass<ImplementationOne> 
{} // doStuff() will return an instance of ImplementationOne 

public class ImplementationTwo 
extends SuperClass<ImplementationTwo> 
{} // doStuff() will return an instance of ImplementationTwo 
관련 문제