2013-10-17 2 views
1

이의 내가 부모 추상 동물 트레이너 클래스를 가지고 있다고 가정 해 봅시다 자체 내에서 정의 된 열거 형을 사용하는 . 나는 구체적인 개 트레이너가 있다면 그래서 다음과 같이 : 나는 단지 DogTrainer.Tricks 유형의 매개 변수에 대한 trainingComplete을 할 수 DogTrainer의 최신 정의강제 아이들은

public class DogTrainer extends Trainer<Dog, DogTrainer.Tricks>{ 
    public enum Tricks implements Trainables { 
    FETCH, GROWL, SIT, HEEL; 
    } 
} 

합니다. 그러나 구체적인 내용을 작성하는 사람은 누구나 Trainer이 자체 내에서 정의하는 Trainables에 대해 trainingComplete()을 허용해야한다고 강조하고 싶습니다. 내가 다른 트레이너가 있다면 즉

, 나의 현재 디자인의 문제는 다음과 같다 :

public class PoliceDogTrainer extends Trainer<Dog, PoliceDogTrainer.Tricks>{ 
    public enum Tricks implements Trainables { 
    FIND_DRUGS, FIND_BOMB, FIND_BODY; 
    } 
} 

개, 경찰 트릭을 가르 칠하려고 다른 루즈 트레이너를 정의에서 사람을 방지 아무것도 없다 :

public class RougeTrainer extends Trainer<Dog, PoliceDogTrainer.Tricks>{ 
... 
} 

나는 이것을 금지하고 확장 클래스가 그들 자신이 지정한 유일한 Trainable을 사용할 수있게하고 싶다.

어떻게하면됩니까?

+0

나는 이것도 내 솔루션에 의해 해결 된 것 같아요 : [이전 질문] (http://stackoverflow.com/questions/19435006/force-children-to-use-enums-defined-within-themselves). – anishthecoder

답변

1

enumpublic으로 만들 수는 있지만 추상 기본 클래스에서는 적용 할 수 없습니다. 또 다른 방법은 Trainer 클래스와 일치해야하는 유형 매개 변수를 추가하여 Trainables을 일반화하는 것입니다. 이것은 enum을 내부 클래스 (불가능 함)로 적용하지 않지만 준수 하위 클래스의 경우에는 RogueTrainer을 만들 수 없습니다.

기본 클래스 또는 인터페이스 내부의 this 유형에 대한 제한을 적용하는 것은 까다 롭고 불가능한 것 사이에 놓입니다. 일반적으로 알려진 예로는 class Foo implements Comparable<String>과 같은 구현을 방지하기 위해 선언 할 수없는 Comparable 인터페이스가 있습니다.

이 문제를 회피하기위한 한 가지 방법은 Trainer 참조를 매개 변수로 만드는 것입니다.

public interface Trainables<T extends Trainer<?,? extends Trainables<T>>> 
… 
public abstract class Trainer 
    <A extends Animal, 
    E extends Enum<E> & Trainables<? extends Trainer<A,E>>> { 

    protected EnumSet<E> completed; 

    void trainingCompleteImpl(E trainable) { 
    completed.add(trainable); 
    } 

    public static <A extends Animal, T extends Trainer<A,E>, 
    E extends Enum<E> & Trainables<T>> void trainingComplete(T t, E trainable) { 
    t.trainingCompleteImpl(trainable); 
    } 
} 

public class PoliceDogTrainer 
    extends Trainer<Dog, PoliceDogTrainer.Tricks> { 

    public enum Tricks implements Trainables<PoliceDogTrainer> { 
    FIND_DRUGS, FIND_BOMB, FIND_BODY; 
    } 
} 

public static 방법은 TrainerTrainables과의 적절한 조합을 호출 할 수있다. trainingCompleteImpl 메소드는 동일한 패키지 내의 신뢰할 수있는 서브 클래스에 의해 호출 및 대체 될 수 있습니다. 이것을 원하지 않으면 메소드의 코드를 인라인하고 인스턴스 메소드를 완전히 제거 할 수 있습니다.

이 _

대안이 Trainer에 대한 유형 매개 변수를 작성하고 런타임시 매개 변수와 this 사이의 일치를 시행하는 것입니다 : 비 부합 Trainer 구현을 위해,

public interface Trainables<T extends Trainer<?,T,? extends Trainables<T>>> 
… 
public abstract class Trainer 
    <A extends Animal, T extends Trainer<A,T,E>, 
    E extends Enum<E> & Trainables<T>> { 

    protected EnumSet<E> completed; 

    /** sub-classes should implements this as {@code return this}*/ 
    protected abstract T selfReference(); 

    void trainingComplete(E trainable) { 
    if(selfReference()!=this) throw new IllegalStateException(); 
    completed.add(trainable); 
    } 
} 
public class PoliceDogTrainer 
    extends Trainer<Dog, PoliceDogTrainer, PoliceDogTrainer.Tricks> { 

    public enum Tricks implements Trainables<PoliceDogTrainer> { 
    FIND_DRUGS, FIND_BOMB, FIND_BODY; 
    } 

    @Override 
    protected final PoliceDogTrainer selfReference() 
    { 
    return this; 
    } 
} 

그래서 selfReference() 수 없습니다 쉽게 검출 될 수있는 return this;으로 구현 될 수있다. 일치하는 구현을 위해 JVM은 selfReference 메소드를 인라인하고 this==this을 보게 될 것이다. 따라서이 검사는 성능에 영향을 미치지 않습니다.

+0

그렇다면'Trainables'는'공용 인터페이스 Trainable '로 정의되어야합니까? 학부모 '강사'에서 어떻게 시행 할 수 있습니까? – anishthecoder

+1

답변을 연장했습니다. – Holger