1

가능한 경우 composition을 사용하여 클래스를 확장하려고합니다. 하지만 특정 문제에 문제가 있습니다.좀 더 특수화 된 생성자 인수가 필요한 composition을 사용하여 클래스를 어떻게 확장합니까?

내가 Base 클래스와 Extending 클래스가 있다고 가정 해 보겠습니다. 연재 클래스는 오히려 우리가 구성을 사용하는 경우 상속보다 기본 클래스의 인스턴스에 걸립니다 우리는 우리의 의존성을 주입 할 : 기본 클래스는 우리가 다음에 사용할 수있는 몇 가지 의존성에 걸리는

public class Base 
{ 
    private ISomeDependency dependency; 

    public Base(ISomeDependency dependency) 
    { 
     this.dependency = dependency; 
    } 

    public ISomeDependency getDependency() 
    { 
     return dependency; 
    } 
} 
public class Extending 
{ 
    private Base base; 

    public Extending(Base base) 
    { 
     this.base = base; 
    } 
} 

getDependency() 메소드를 사용하여 클래스를 확장한다.

그러나 우리가 확장 클래스에서 필요로하는 ISomeDependency의 하위 유형을 전문화하려면 어떻게해야합니까?

public class Extending extends Base 
{ 
    private ISomeDependencySubtype dependency; 

    public Extending(ISomeDependencySubtype dependency) 
    { 
     super(dependency); 
     this.dependency = dependency; 
    } 
} 

을하지만 우리는 구성을 사용하는 경우 것은 다음이 더 어려워진다 :

것은 우리가 단순히과 같이 슈퍼 클래스 생성자에 하위 유형을 전달할 수 상속을 사용한 경우.

public class Extending 
{ 
    private ISomeDependencySubtype dependency; 
    private Base base; 

    public Extending(Base base, ISomeDependencySubtype dependency) 
    { 
     base.init(dependency); 
     this.base = base; 
     this.dependency = dependency; 
    } 
} 

이 옵션은 확장 클래스는 자료에 초기화() 메소드를 사용한다는 사실을 숨 깁니다 자료의 생성자 대신 초기화 방법을 가졌 : 나는 여러 옵션의 생각 인터페이스가 아마도 불분명해질 것입니다. Extending 클래스를 사용할 때 다른 프로그래머는 Base 인스턴스가 Extending 인스턴스로 전달되기 전에 init()을 호출해야한다고 가정 할 수 있습니다.

이 제네릭의 남용 것 같아 일반적인 인수

public class Base<T extends ISomeDependency> 
{ 
    private T dependency; 

    public Base(T dependency) 
    { 
     this.dependency = dependency; 
    } 

    public T getDependency() 
    { 
     return dependency; 
    } 
} 

public class Extending 
{ 
    private ISomeDependencySubtype dependency; 
    private Base<ISomeDependencySubtype> base; 

    public Extending(Base<ISomeDependencySubtype> base) 
    { 
     this.base = base; 
     this.dependency = base.getDependency(); 
    } 
} 

추가. Base 클래스가 자체적으로 클래스이고 Extending 클래스없이 사용할 수있는 경우 ISomeDependency의 하위 유형이 전달 될 때주의해야합니다. 일반적인 인수는이 시나리오를 수용하기 위해 모든 것이 리팩토링되어야 함에도 불구하고이 특정 시나리오에만 존재할 것입니다.

public class Extending 
{ 
    private ISomeDependencySubtype dependency; 
    private Base base; 

    public Extending(ISomeDependencySubtype dependency) 
    { 
     this.base = new Base(dependency); 
     this.dependency = dependency; 
    } 
} 

이 확장 내부

인스턴스화 자료

베이스 인스턴스 의존성이 주입 될 수있는 수단에 전달 될 수 없다는 것을 의미한다. 이것은 아마도 가장 명백한 이유 때문에 융통성이 없습니다.

저는 사람들이이 문제를 극복하기 위해 구성을 사용하는 것이 가장 바람직하다고 생각합니다. (상속 기반 답변 없음).

+1

예를 들어 가끔씩 '확장베이스'가 포함되어 있습니다. – 5gon12eder

+0

잘 찾아 냈습니다. 편집 할 것입니다. – Jonathan

답변

0

이것은 공변 의존성이있는 모든 문제와 마찬가지로 다소 병적 인 문제이며 완전한 해결책이 될 수 없습니다.

솔루션 외에도에만 Base의 종류와 Extending의 생성자에 ISomeDependency의 인스턴스를 전달하고 동적으로 Base 객체를 생성 할 수있다.

public class Extending { 

    // Keep an additional copy (ugly and probably unsafe). 
    final dependendcy dependendcy; 
    final Base base; 

    public Extending(final Class<? extends Base> cls, 
        final ISomeDependencySubtype dependendcy) throws Exception { 
     this.dependency = dependency; 
     this.base = cls.getConstructor(ISomeDependency.class).newInstance(dependency); 
    } 
} 

이것은 당신이 자바의 타입 시스템에 의해 정적으로 시행 할 수없는 Base의 적절한 생성자를 가정해야 할 명백한 단점이있다.

원한다면 기본 생성자 (보다 쉬운 요구 사항처럼 보일 수도 있음)를 가정 한 다음 종속성이있는 init 메서드를 호출 할 수 있습니다. [init 메서드가 마음에 들지 않습니다.] 이렇게하면 Base이 호출자에 의해 초기화되어야하는지 여부의 모호성을 제거합니다. 보장이 없기 때문에 의존성에 대한 추가 참조를 유지에 의존

모든 솔루션은 Base 그렇게

assert this.dependency == this.base.getDependency(); 

이 잘되지 않을 수 있습니다 개체를 대체하지 않습니다 내 의견에 안전하지. 물론,
assert this.base.getDependency() instanceof ISomeDependencySubtype; 

뿐만 아니라 실패 할 수 있습니다, 같은 이유 때문에 getDependency에 의해 반환되는 참조를 다운 캐스트되지 않은 안전합니다.

Extending extends Base (원하지 않는다고하더라도)이 문제는 더 좋아지지 않습니다.

제네릭 접근 방식으로이 문제를 해결할 수 있지만 다른 모든 종류의 문제가 발생합니다.

완벽한 솔루션이 존재하지 않는다고 생각하기 때문에 악의를 받아들이는 실제 사용 사례에 크게 의존합니다.

+0

감사합니다. 잠시만 기다려 주시면 제가 옳은 대답을 선택하기에 앞서 생각합니다.하지만 당신이 옳다고 생각합니다. 마법의 해결책은 없습니다. – Jonathan

관련 문제