2011-01-19 2 views
1

현재 시뮬레이션 프로젝트의 클래스 계층 구조를 설계하고 있습니다. 이것은 Element 인스턴스 트리의 개별 이벤트 시뮬레이션입니다. 간결성을 위해 (그리고 나는 단지 문제의 generics 부분에만 관심이 있기 때문에) 여기서 클래스/인터페이스의 스케치를 제시 할 것이므로 구문이 완벽하지는 않을 것이다. 시작하는 뭔가를하기 위해, 요소는 다음과 같습니다Generic을 사용하여 컨테이너 제한

public abstract class Element { 
    private Set<Element> children = new HashSet<Element>(); 
    public Element getContainer(); 
    public Collection<Element> getChildren() { 
     return Collections.unmodifiableSet(children); 
    } 
    public Position getPosition(); 
    protected void add(Element e) { children.add(e); } 
    protected void remove(Element e) {children.remove(e); } 
} 

Position의 정의는 정말 중요하지 않습니다, 그리고 어떤 다른 방법은 어떻게해야되는 것은 자명 나는 희망이다.

public abstract class Solid extends Element { 
    public Size getSize(); 
} 

가 다시 Size의 정확한 의미는 중요하지 않습니다하는 Solid 단지 시뮬레이션 세계의 공간을 채우는 물리적 객체 있어야하는데 : 우리가 풀에 다른 인터페이스를 던져 상황이 약간 흥미로운 확인하십시오.

public abstract class Stack extends Solid { 
    public void add(Solid s); // <- trouble ahead! 
} 

을 그리고 여기에 문제가 시작 어디 : 지금 우리가 가지고있는 것을 우리가 여기에, 서로의 위에 그들을 스택 할 수 있습니다 고체 객체는 Stack입니다. Solid의 인스턴스 만 Stack에 추가하려고합니다. 크기가없는 객체를 쌓기가 어렵 기 때문에 Stack에는 Size이 필요한 항목이 필요합니다. 그러므로 나는이 표현 할 수 있도록 내 Element 재 작업 : 여기

public abstract class Element<E extends Element<?>> { 
    private final Set<E> children = new HashSet<E>(); 
    public Element<?> getContainer(); 
    public Collection<E> getChildren(); 
    public Position getPosition(); 
    public void add(E e); 
    public void remove(E e); 
} 

내 의도가 Element가 포함 할 수있는 (하위) Element의 종류에 제한이있을 수 있음을 표현하는 것입니다. 지금까지이 모든 것이 작동합니다. 하지만 지금은 컨테이너에 대한 제한이 필요하다고 느꼈습니다. Element입니다. 그게 어떻게 생겼어?

public interface Element<E extends Element<?,?>, C extends Element<?, ?>> 

아니면이 같은 더 갈 않습니다 나는 이것에 대해 퍼지 조금을 느낄 시작하고, 게임에 더있다

public interface Element<E extends Element<?,C>, C extends Element<E, ?>> 

: 거기가

  • 은 하나의 컨테이너에서 다른 컨테이너로 요소를 전송하는 "포트"(InputOutput)가 있어야합니다. 나는 이것들에 제네릭 마법을 던져야 할 것이다.
  • 내 할 일 목록에 모델 용 GUI 편집기가 있습니다. 따라서 런타임에이 체크를 사용할 수있게해야합니다. 그래서 나는 타입 리터럴과 같은 것 같아요 public boolean canAdd(Element<?, ?> e) 편집기에 의존해야합니다. 이 방법은 매우 중요하기 때문에 클래스의 final 메서드를 사용하고 싶습니다. 따라서 술취한 개발자는 오전 4시에 잘못 입력 할 수 없습니다.
  • 서브 클래스가 Element 인 경우에는 Collection 클래스를 사용하기로 결정할 수 있습니다. 왜냐하면 일부는 LinkedList이거나 완벽하게 보이기 때문입니다.
    • 내가 다시 발명 바퀴를 오전 :

    그래서 여기 내 질문입니까? 저를 위해 어떤 도서관이 있습니까?

  • 제네릭으로이 문제를 해결할 수 있습니까? (대답이 '예'인 경우 : 구현에 대한 몇 가지 힌트를 환영합니다.)
  • 조금 지나치게 엔지니어링 될 수 있습니까?
  • 이 질문에 더 나은 제목이나 태그가 있습니까? :-)
+0

여기 당신을위한 생각입니다. Java의 범용 클래스의 목적은, ClassCastException를 막는 것입니다. 마침표. 그것은 그들이 정상적인 방법으로하는 유일한 것입니다. 다른 용도로 사용하려는 경우, 그 방법은 광기가됩니다. – Affe

+0

"그 방법은 광기에있다", 하하 .. 타입 삭제를 이해하기 전에 나는 제네릭으로 모든 종류의 야생 트릭을 시도했지만, 대부분은 제네릭의 창조적 인 사용이 실패 할 운명이라고 배웠다. 요소 처럼 C가 미친 것처럼 보이면 C는 요소 을 확장합니다> 이러한 요소를 사용하는 것에 회의적이어야합니다. 이러한 용도를 개념화하는 것은 너무 어렵습니다. –

+0

@Affe 여기서 내가하려고하는 목적은 궁극적으로 CCE를 예방하는 것입니다. getSize()가있는 요소에서만 작동 할 수있는 스택에 대해 생각해보십시오. 이는 솔리드입니다. 따라서 제네릭을 사용하여이를 표현하면 컴파일러는 이것이 정상인지 확인합니다. 그렇지 않으면 캐스팅이 유효한지 확인하기 위해 캐스팅하고 다른 방법을 찾아야합니다. – Waldheinz

답변

1

나는 아직도 당신이 뭘하려고하는지에 관해서 조금 퍼지 해요,하지만 당신은 그것의 논리적 인 결론이 모든 방법을 실행하려는 경우,이 같은보고 있어요 :

/** 
@param P parent 
@param C child 
@param S self 
*/ 
interface Element<P extends Element<?, S, P>, 
     C extends Element<S, ?, C> , 
     S extends Element<P, C, S>> { 
    public P getParent(); 
    public Collection<C> getChildren(); 
} 

모든 제약 조건을 표현하면 (내 생각에) 부모는 저를 어린 시절에 가질 수있는 것이어야하며 자녀는 저를 부모로 가질 수 있어야합니다.

구현이 포함됩니다 :

/** An agglomeration of stacks: no parent */ 
class Agglomeration extends Element<?, Stack, Agglomeration> {…} 

/** A stack of solids */ 
class Stack extends Element<Agglomeration, Solid, Stack> {…} 

/** A solid in a stack: no children */ 
class Solid extends Element<Stack, ?, Solid> {…} 

내가이없는 자바 IDE 열려있는 지금,하지만, 그래서 나는 실제로 컴파일이 확신 할 수 없습니다 - 나는 컴파일러가 불평하는 느낌이 그 물음표에 대해, 당신은 별도의 인터페이스 (getChildren() 하나와하나에 ParentChild을 분리하는 경우 당신은,하지만, 그 주위에 얻을 수

class Agglomeration extends Element<? 
    extends Element<? 
     extends Element<? 
      extends... 

처럼 뭔가를 끌어 시도 3200)이므로 Agglomeration은 첫 번째로만 구현되고 Solid은 두 번째로만 구현되며, Stack에서는 두 번째를 구현합니다.

그것은 가치가있는 것보다 더 많은 어려움이있을 수 있지만 잠시 동안 실행하고 그것이 당신에게 필요한 곳을 참조하십시오. :)

+0

지금까지 말할 수있는 한, "자체"라는 개념은 나는 지금까지 가지고 있던 것과 "실종 된"링크를 매우 사실적으로 느낀다. 당신이 제안한 인터페이스를 약간 변경해야만했습니다. 현재 인터페이스 Elem

, C extends Elem , S extends Elem > {/ * ... * /}'을 사용하여, 나는 그것이 나를 필요로한다. :-) 지금까지 많이 고마워! – Waldheinz

0

내가 당신의 디자인에 대한 이해에이 답변을 내놓고있어 (여기 의견을 드롭). 내 이해가 틀렸다면 알려주세요!

제네릭의 주된 목적은 유형 안전성을 보장하고 객체 관계가 아니라는 것입니다 (필자가 아는 한). 유형 안전을 보장하여 객체 간의 관계를 향상시킬 수있는 것처럼 보이지만 궁극적으로는 유형 안전성을 보장하는 것입니다 (따라서 사용자가 속하지 않는 곳에 고정하지 않아야합니다).

추상적 인 수업에서는 add이라는 메서드를 제공했습니다. 즉,이 추상 클래스를 확장하는 모든 요소는 add을 구현해야합니다. 이제 나중에 add에 대한 제한을 부과합니다. addSolid 개체 (Element의 하위 클래스) 만 가능합니다. 그러나 그 일을 할 때, 당신은 (또는 그 서브 클래스)가 세트에 추가 될 수 있다고 말하는 추상 클래스의 계약을 위반하고 있습니다.

두 가지 옵션이 있습니다. 디자인을 다시 생각해야합니다 (어쩌면 add을 추상 클래스에서 제공하면 안됩니까?). 다른 옵션으로는 크기가없는 객체 인 add을 시도 할 때 런타임 예외 (UnsupportedOperationException)가 발생하고 개발자가 특정 객체를 추가 할 수 있는지 여부를 알 수있는 검사 메소드 (예 : canAdd)가 제공됩니다.

1

그냥 어떤 임의의 말 : 당신이 나 Collection<? extends E>을하지 않을 수 있습니다

대신 Collection<E>의.

저는이 유형을 캡처하고자하므로 Element<E extends Element<**E**>으로 시작하고 싶습니다 (java.lang.Enum을 살펴보십시오). 따라서 Element<E extends Element<E,C>, C extends Element<C, ?>> 과 같은 것이 필요할 수도 있습니다. 컴파일러와 컴파일러 모두에 너무 복잡 할 수 있습니다 (어쩌면 더 좋을 수도 있지만 너무 힘들 때 약간의 오류가 나타납니다).

아마도 Element.add 및 Stack.add 메소드가 실제로 다른 메소드입니까? Stack에 children을 추가하는 것은 그것들을 스태킹하는 것을 의미합니다. 임의의 Element에 추가하는 것은 완전히 다른 것을 의미 할 수 있습니다.

일부 LinkedList 또는 완벽하게 적합하기 때문에 Element 클래스의 하위 클래스가 자신이 사용하는 Collection 클래스를 결정할 수 있으면 멋질 것입니다.

기본 클래스의 ctor에서 호출되는 Collection<C> makeCollection()과 같은 메소드가 수행 할 수 있습니다. 그러나 LinkedList를 사용하는 것은 대부분 시간이 잘못되었습니다 (잘못된 공간 지역성 및 높은 공간 오버 헤드로 인해 느려지므로 이점이 무시 될 수 있습니다).

그래서 이러한 검사는 런타임에 제공해야합니다.

따라서 Class<E> 매개 변수를 사용하여 인스턴스를 구성해야합니다.

return Collections.unmodifiableSet (children);

이렇게하면 어린이의 라이브 뷰를 반환합니다. 대신 com.google.common.collect.ImmutableSet.copyOf (하위)를 사용해보십시오.

0

이 라인에서 상대 :

public interface Element<E extends Element<?,?>, C extends Element<?, ?>> 

은 내가 설계를 통해 - 예,이 확실하다고 생각했다.

물론 상황에는 여러 가지가 있지만 나에게 유익한 소리는 상속 대신에 Decorator 패턴을 사용하는 것입니다 (어디서나 본래의 디자인이 닳았다는 느낌이 드는 곳에서만 사용 가능합니다) 더 잘 들어 맞을 것이다.

관련 문제