2012-09-14 2 views
2

그래서 인터페이스가 SuperType이고 클래스를 구현하는 경우 TypeA, TypeB 등이 있습니다. GeneralProduct를 구현 내가 공장을 가지고 캐스트하지 않고도 제네릭 인터페이스를 구현하는 특정 클래스의 팩토리를 얻으려면 어떻게해야합니까?

public interface UsedByProductThing<T extends SuperType> { 
    public T doStuff(T one); 
} 

(아래 참조) 생산 제품 : : 여기

public interface GeneralProduct<T extends SuperType> { 
    T doSomething(T input); 
} 

ProductA 구현된다

또한 매개 변수화 된 방법이있는 최상위 인터페이스를 가지고
public class ProductA implements GeneralProduct<TypeA> { 
    UsedByProductThing<TypeA> in; 

    public ProductA(UsedByProductThing<TypeA> in) { 
     this.in = in; 
     in.doStuff(new TypeA()); 
    } 

    @Override 
    public TypeA doSomething(TypeA input) { 
     return null; 
    } 
} 

이제 문제의 공장 :

public class GeneralFactory { 
    public static <T extends SuperType> GeneralProduct<T> createProduct(
      int type, UsedByProductThing<T> in) { 
     switch (type) { 
     case 1: 
      return (GeneralProduct<T>) new ProductA((UsedByProductThing<TypeA>) in); 
      // at this point, i want to return a "new ProductA(in)" preferably 
      // without casting 
      // or at least without the cast of the argument. 
     default: 
      throw new IllegalArgumentException("type unkown."); 
     } 
    } 
} 

주석으로, 나는 factory-method가 캐스트를 사용하지 않기를 바란다. 반환 유형이 GeneralProduct 여야한다는 것을 알고 있지만 캐스트를 생략하는 방법을 생각할 수 없습니다 (그리고 이는 나에게 "확인되지 않은 캐스트"- 경고도 함). 또한, 나는 논쟁의 캐스트를 생략하는 방법을 생각할 수 없다. 그 장소에서 "안전하지 않은"캐스팅을 제거해야하는 경우 전체 코드를 재구성 할 수 있습니다. 여기에 친절하고 매끄러운 방법을 말해 줄 수 있어요?

또한 원하는대로 질문을 편집하십시오. 제목에서 문제를 올바르게 해결하는 방법을 모르겠습니다.

고마워요!

+1

왜 반환 유형의 캐스트를 없애고 싶지는 모르겠지만 괜찮습니다. 안전하지 않은 매개 변수에 대해서는 사용자가'type'에'1'을 전달하면 항상'UsedByProductThing '을 전달한다는 가정을하기 때문입니다. 사용하는 코드가 항상이 계약을 만족한다는 것을 아는 경우라면 괜찮습니다. 그렇지 않으면 문제가 있습니다. –

+0

한 가지 기억해야 할 점은 type-erasure로 인해 모든 제네릭 형식이 런타임에'Object'로 변환된다는 것입니다. 따라서'UsedByProductThing'은'UsedByProduceThing '이되고'GeneralProduce'는'GeneralProduce '이됩니다. 일반적인 캐스팅을 다루는 서클에서 일하기 전에 이것을 명심하십시오. –

+0

유형 삭제에 대해 알고 있습니다. 제네릭이 있기 전에는 Java를 사용하지 않았기 때문에 그러한 유형의 (형용사) 유형 캐스팅이 실제로 필요한 지점에 도달하지 못했습니다. 또한'((UsedByProductThing ) in '과 같은 캐스트가 왜'in' 유형이'(UsedByProductThing )'입니까? 내가 올바르게 이해했다면, 타입 지우기 전에 컴파일러를위한 것이고 그 후에는 완전히 생략됩니다 - 맞습니까? – Mitja

답변

4

  • 는 당신이 UsedByProductThing<TypeA>로 전환 할 UsedByProductThing<T>을 입력있다 in을 가지고 컴파일러가 TTypeA
  • ProductA이 GeneralProduct<TypeA> 인 것을 알 수있는 방법이 없기 때문에 당신은 캐스팅을 피할 수 없다 그리고 컴파일러는 이 TypeA임을 알지 못합니다.

캐스트를 피할 수있는 유일한 방법은 내가이 일을 어떤 청소 방법이 확실하지 않다 TypeA

public static GeneralProduct<TypeA> createProduct(
      int type, UsedByProductThing<TypeA> in) { 
     switch (type) { 
      case 1: 
       return new ProductA(in); 
      default: 
       throw new IllegalArgumentException("type unkown."); 
     } 
    } 
+0

내 createProduct-method를 쓸모 없게 만들 것입니다. 그 점을 분명히 해주셔서 대단히 감사합니다! – Mitja

0

T을 교체하는 것입니다. 또한 누군가가 "in"값과 호환되지 않는 "type"값을 전달할 수 있기 때문에 당신이 그것을하고있는 것처럼 캐스팅하는 것이 어쨌든 본질적으로 안전하지 않다고 생각합니다.

이러한 종류의 내재적 인 확인되지 않은 캐스트는 제네릭을 다룰 때 흔히 사용됩니다. 당신은 가능하다면 그것들을 피해야한다. 그러나 때때로, 당신은 할 수없고 단지 컴파일러 경고를 없애기를 원한다면 주석을 추가해야한다.

다른 방법이 왜 빌더 접근을하지

@Suppress ("선택 해제")?

Builder<ProductA> builder = BuilderFactory.createBuilder(ProductA.class); 
UsedByProductThing<ProductA> thing = ...; 
ProductA product = builder.createProduct(thing); 
+0

고마워, 나는 빌더 개념을 시도 할 것이다. – Mitja

0

"GeneralProduct<T>" 

을 반환 해달라고, 더 나은 당신이

"GeneralProduct<?>" 

반환 :

public inteface Builder<T extends SuperType> { 
    public GeneralProduct<T> createProduct(UsedByProductThing<T> thing); 
} 

public class BuilderFactory { 
    public static <T extends SuperType> Builder<T> createBuilder(Class<T> clazz) { 
     if (clazz.equals(ProductA.class)) { 
      return new (Builder<T>) ProductABuilder(); 
     } 
     ... 
    } 
} 

그리고 당신이 빌더 imple을 만든 가정 (예 : 사용 결과를 캐스팅 할 필요가 없습니다.

하지만 어쨌든 "ProductA"에 대한 매개 변수를 캐스팅해야합니다!

관련 문제