1

假设我有一个父级抽象动物训练师课程:

public abstract class Trainer 
  <A extends Animal, 
   E extends Enum<E> & Trainables>{
    protected EnumSet<E> completed;
    public void trainingComplete(E trainable){
      trainingComplete.add(trainable);
    }

我希望对父级动物训练师进行具体扩展,以仅完成对其定义的可训练对象的训练。因此,如果我有一个具体的训狗师,如下所示:

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

用当前定义的DogTrainerI 只能trainingCompleteDogTrainer.Tricks类型的参数做。但我想强制任何创建混凝土的人都应该Trainer允许它在自身内部定义。trainingComplete()Trainables

换句话说,我当前设计的问题是,如果我有另一个训练器,如下所示:

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>{
 ...
}

我想禁止这样做并允许扩展类仅使用他们自己指定的可训练对象。

我怎样才能做到这一点?

4

1 回答 1

1

您可以将enums 设为非public,但这不能由抽象基类强制执行。另一种方法是Trainables通过添加必须与类匹配的类型参数来实现泛型Trainer。这并不强制将enum其作为内部类(这是不可能的),但是对于符合要求的子类,RogueTrainer则不能创建 no 。

对基类或接口内部的类型实施约束this介于棘手和不可能之间。一个众所周知的例子是Comparable接口,它不能以阻止实现的方式声明,如class Foo implements Comparable<String>.

规避此问题的一种方法是将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方法只能通过 和 的正确组合Trainer调用Trainables。该trainingCompleteImpl方法可以由同一包中的受信任子类调用和覆盖。如果您不希望这样做,您可以内联方法的代码并完全删除实例方法。

_

另一种方法是创建一个类型参数,Trainer并在参数和this运行时强制匹配:

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;
  }
}

因此,对于不合格的Trainer实现selfReference(),无法实现,因为return this;它可以很容易地检测到。对于符合要求的实现,JVM 将内联该selfReference方法,this==this然后查看哪些将被优化掉;所以这个检查对性能没有影响。

于 2013-10-17T19:36:06.130 回答