强迫孩子使用自己内部定义的枚举



假设我有一个家长抽象动物训练师班:

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

使用当前的DogTrainer定义,我只能对DogTrainer.Tricks类型的参数执行trainingComplete。但我想强调的是,任何创建具体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>{
 ...
}

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

我该怎么做?

你可以使enumpublic,但这不能由抽象基类强制执行。另一种方法是通过添加必须与Trainer类匹配的类型参数来使Trainables泛型。这不会强制enum成为内部类(这是不可能的),但对于符合标准的子类,则无法创建RogueTrainer

对基类或接口内的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方法只能通过 TrainerTrainables 的正确组合来调用。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,然后哪些方法将被优化;因此,此检查对性能没有影响。

相关内容

  • 没有找到相关文章

最新更新