假设我有一个家长抽象动物训练师班:
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>{
...
}
我想禁止这样做,并允许扩展类仅使用他们自己指定的可训练对象。
我该怎么做?
你可以使enum
不public
,但这不能由抽象基类强制执行。另一种方法是通过添加必须与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
方法只能通过 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
,然后哪些方法将被优化;因此,此检查对性能没有影响。