2014-11-13 2 views
5

저는 API 디자인을 연구하고 있습니다. 지금까지 생각하지 못했던 Java 및 다형성에 대해 뭔가 있습니다. 나는이 같은 API를 만드는 경우 :Java, 다형성, 정적 입력 및 "QueryInterface"패턴

interface FooFactory 
{ 
    public Foo getFoo(); 
} 

interface Foo 
{ 
    public void sayFoo(); 
} 

는 내 FooFactory 구현을 제공하기 위해 의존 할 수있는 유일한 일은 Foo 구현입니다. 나는 다음과 같이 몇 가지 개선 된 방법을 제공하기로 결정하는 경우 :

interface EnhancedFoo extends Foo 
{ 
    public void patHeadAndRubBelly(); 
} 

class EnhancedFooImpl implements EnhancedFoo 
{ 
    ... implementation here ... 
} 

class EnhancedFooFactoryImpl implements FooFactory 
{ 
    @Override public EnhancedFoo getFoo() { return new EnhancedFooImpl(); } 
} 

을하고 그들이 Foo 인터페이스를 획득하고 EnhancedFoo로 캐스팅하려고하면 내 API 클라이언트가 EnhancedFoo 인터페이스를 사용할 수있는 유일한 방법입니다.

HRESULT QueryInterface(
    [in] REFIID riid, 
    [out] void **ppvObject 
); 

아이디어는 당신이 성공하면, 당신은 당신을 보장하는 포인터를 얻을, 당신이 원하는 인터페이스에 대한 GUID를 전달한다는 것입니다 :

나는 마이크로 소프트가 IUnknown 인터페이스에서 COM을 처리하는 방법을 기억 찾고 있던 인터페이스로 안전하게 전송할 수 있습니다.

내가 자바 형태 보증 된 방법으로 비슷한 뭔가를 할 수 : 나도 원하는 서브 인터페이스의 인스턴스를 반환하거나 사용할 수없는 경우는 null 반환 요청에 대한 구현을 제공

interface FooFactory 
{ 
    public <T extends Foo> T getFoo(Class<T> fooClass); 
} 

.

내 질문입니다 :

  • 는 QueryInterface를 패턴은 합리적이다?
  • 그냥 캐스팅을 사용해야합니까?
  • 또는 클라이언트가 문제의 일반 메소드를 엄격하게 사용하도록 제한하기 위해 API에서 다형성을 처리하는 유일한 방법은 무엇입니까? (예를 들어, 내 예 Foo의 방법이 아닌 모든 EnhancedFoo 방법)

명확한 설명 : 공장 구현 클라이언트 코드에 의해 알려진하지 않을. (종속성 삽입 또는 Java의 ServiceLoader 또는 NetBeans Lookup과 같은 일부 서비스 공급자 아키텍처를 사용한다고 가정 해 봅시다.) 클라이언트로서, 나는 무엇이 사용 가능한지 잘 모릅니다. 팩토리는 여러 개의 Foo 파생물에 액세스 할 수 있으며 클라이언트가 원하는 기능 세트를 요청할 수있게하고 그 중 하나를 가져 오거나 기본 Foo 기능으로 되돌려 야합니다.

내게 힘든 부분은 여기에 런타임 종속성이 있다는 것입니다. 모든 것이 컴파일 타임에 고정되어있는 순수 정적 유형 안전 접근 방식은 기본적인 Foo 기능에만 의존 할 수 있다는 것을 의미합니다. 그 접근법은 내게 친숙하지만, 가능한 향상된 기능을 놓치고 있습니다. 보다 역동적 인/기회 주의적 접근 방식은 이러한 기능을 활용할 수있는 것이지만,이를 사용하는 시스템을 설계하는 올바른 방법은 확실하지 않습니다.

답변

1

당신은 단순히 제네릭으로 공장을 선언하고 그대로 나머지를 떠날 수 :

static interface FooFactory { 
    public <T extends Foo> T getFoo(); 
} 

은 그런 추론을 입력 덕분에,이 컴파일 :

FooFactory f = new EnhancedFooFactoryImpl(); 
EnhancedFoo e = f.getFoo(); 

(이 이전에 작동하지 않을 수 있습니다 Java 8)

FooFactory이 예상 한 것과 다른 경우 EnhancedFoo e = f.getFoo(); 줄은 ClassCastException이됩니다.

+0

Java 8에서 형식 유추가 향상되었습니다. – assylias

+0

흠 ... 예외 접근 방식은 Python에서는 정상이지만 Java에서는 적합하지 않은 것처럼 보입니다. –

+0

나는 그것이 완벽하게 적절하다고 말하고 싶다 - null-checking보다 좋다. – Arkadiy

1

왜 매개 변수를 지정하지 않습니까? 다음

static interface FooFactory<T extends Foo> { 
    public T getFoo(); 
} 

:

class EnhancedFooFactoryImpl implements FooFactory<EnhancedFoo> { 

    @Override 
    public EnhancedFoo getFoo() { return new EnhancedFooImpl(); } 
} 

그리고 인스턴스 :

FooFactory<EnhancedFoo> f1 = new EnhancedFooFactoryImpl(); 
EnhancedFoo foo = f1.getFoo(); 

기본 클래스가 예상되는 곳 물론 향상된 공장 사용할 수 있습니다. (귀하의 의견에 대한 회신에)

FooFactory<?> f2 = new EnhancedFooFactoryImpl(); 
Foo foo = f2.getFoo(); 

편집 디자인에이 매개 변수화 공장 방법을 가지고 더 나은 경우

하지 팩토리 클래스는 다음 아래와 같이 그것을 정의하는 것이 좋습니다 :

interface FooFactory { 

    public <T extends Foo> T getFoo(Class<T> fooClass); 
} 

이렇게하면 두 가지 이점을 얻을 수 있습니다. 1. 사용자가 만들려는 액추에이터 클라스를 제어 할 수 있습니다. 2. 클래스 개체를 사용하면 리플렉션을 통해 인스턴스를 생성 할 수 있습니다. 일부 푸 구현이 생성자 매개 변수를 필요로하는 경우

FooFactory ff = new FooFactoryImpl(); 
EnhancedFoo ef = ff.getFoo(EnhancedFoo.class); 
Foo f = ff.getFoo(Foo.class); 

:

class FooFactoryImpl implements FooFactory { 

    @Override 
    public <T extends Foo> T getFoo(Class<T> c) { 
     try { 
      return c.newInstance(); 
     } catch (ReflectiveOperationException e) { 
      return null; 
     } 
    } 
} 

그런 다음 사용은 다음과 같다 :

그래서이 경우 당신은 강화 foo에 대한 특별 공장 클래스에있을 필요 없다 foctory 메서드에있는 경우 항상 해당 객체를 "수동"으로 인스턴스화 할 수 있습니다.

@Override 
    public <T extends Foo> T getFoo(Class<T> c) { 

     if(SomeParametrizedFoo.class.equals(c)) { 
      SomeParamtrizedFoo spf = new SomeParamtrizedFoo("constr arg"); 
      spf.setParam(16136); 
      return (T) spf; 
     } 

     try { 
      return c.newInstance(); 
     } catch (ReflectiveOperationException e) { 
      return null; 
     } 
    } 
+0

내 생각에 클라이언트가 사용하고자하는 특정 기능이 있다고 생각한다. 'Foo' 클래스에는 하나 이상의 확장 기능이있을 수 있으므로 공장에 맡기고 싶지는 않습니다. 대신 고객에게 달려 있어야합니다. 나는 API 디자인에 대해 충분히 경험하지 못하여 정확하게 내 질문을 형성하는 방법을 100 % 확신하지 못했습니다. –

+0

에 설명이 추가되었습니다. –

+0

@JasonS 제 수정 사항에서 언급했습니다. –