假设我有一个抽象类
public abstract class Trainer<T extends Animal>{}
我有特定的培训师:
public DogTrainer extends Trainer<Dog>{}
public HorseTrainer extends Trainer<Horse>{}
这些'训练师'中的每一个都有一套固定的技巧,他们可以训练动物去做,我想使用Enums。所以我有一个界面:
public interface TrainingActions<T extends Animal>{}
在每个培训师中,我都有一个实现此界面的Enum。所以:
public DogTrainer extends Trainer<Dog>{
public enum Trainables implements TrainingActions<Dog>{
BARK, BITE, ROLLOVER, FETCH;
}
}
public HorseTrainer extends Trainer<Horse>{
public enum Trainables implements TrainingActions<Horse>{
JUMP, TROT, REARUP;
}
}
现在在每个Trainer类中,我想要一个方法说'trainingComplete',它将一个Enums作为输入并将其保存到一个集合中。所以
public DogTrainer extends Trainer<Dog>{
public enum Trainables implements TrainingActions<Dog>{
BARK, BITE, ROLLOVER, FETCH;
}
public Set<Trainables> completed = new HashSet<Trainables>();
public void trainingComplete(Trainables t){completed.add(t);}
}
但是,我不想在每个培训师中定义每个特定培训师和'trainingComplete'方法中的'已完成'集合,而是希望父母'培训师'课程中的某些内容可以强制执行Enum类型...所以它是Enums和泛型的奇怪组合。
这可能吗?
答案 0 :(得分:28)
要指定接口的绑定并且它是枚举,您需要一个通用的交集,它看起来像:
class MyClass<T extends Enum<T> & SomeInterface> {}
请注意,当与类和接口相交时,该类必须出现在接口之前。
在这种情况下,你想要的仿制功夫是一个更复杂的级别,因为TrainingActions枚举的界面本身必须参考动物类型。
class Trainer<A extends Animal, T extends Enum<T> & TrainingActions<A>> {}
一个完整的工作示例,基于您发布的代码,编译为:
public class Animal {}
public interface TrainingActions<T extends Animal> {}
/**
* A trainer that can teach an animal a suitable set of tricks
* @param <A> The type of Animal
* @param <T> The enum of TrainingActions that can be taught to the specified Animal
*/
public abstract class Trainer<A extends Animal, T extends Enum<T> & TrainingActions<A>> {
private Set<T> completed = new HashSet<T>();
public void trainingComplete(T t) {
completed.add(t);
}
}
public class Dog extends Animal {};
public class DogTrainer extends Trainer<Dog, DogTrainer.Trainables> {
public enum Trainables implements TrainingActions<Dog> {
BARK, BITE, ROLLOVER, FETCH;
}
}
但我会更进一步,在它们适用的特定TrainingActions
的类中定义几个Animal
枚举:
public class Dog extends Animal {
public enum BasicTrainables implements TrainingActions<Dog> {
SIT, COME, STAY, HEEL;
}
public enum IntermediateTrainables implements TrainingActions<Dog> {
BARK, BITE, ROLLOVER, FETCH;
}
public enum AdvacedTrainables implements TrainingActions<Dog> {
SNIFF_DRUGS, FIND_PERSON, ATTACK, GUARD;
}
};
public class PuppyTrainer extends Trainer<Dog, Dog.BasicTrainables> {}
public class ObedienceTrainer extends Trainer<Dog, Dog.IntermediateTrainables> {}
public class PoliceTrainer extends Trainer<Dog, Dog.AdvacedTrainables> {}
答案 1 :(得分:1)
尽管进行了设计分析,但我认为最适合您的情况(最接近您已创建的设计)的答案是:
DogTrainer.Trainables
是TrainingActions<Dog>
HorseTrainer.Trainables
是TrainingActions<Horse>
通常,您的Trainables
已经是TrainingActions<T extends Animal>
所以您可以提供Set<TrainingActions<T>> completed
,因为您已经在T
中获得了您的动物信息:
abstract class Trainer<T extends Animal> {
Set<TrainingActions<T>> completed = new HashSet<TrainingActions<T>>();
public void add(TrainingActions<T> t ) {
completed.add( t );
}
}
你有你想要的。
用法:
DogTrainer tr = new DogTrainer();
tr.add( DogTrainer.Trainables.BITE );
如果您确定要为您的界面强制执行Enum:
public <E extends Enum<?> & TrainingActions<T>> void add( E t ) {
completed.add( t );
}
答案 2 :(得分:1)
即使已经接受了答案
,我也会将其发布以供进一步考虑如果您阅读此问题,请考虑使用更多松散耦合元素,使用聚合等,而不是使用高度特定和复杂的类型层次结构和泛型。
通过简单的聚合,您可以实现至少相同的类型&amp;逻辑安全,但松耦合设计。就像我在评论中提到的那样:
更好的是更多的收藏品,聚合物等确保 类型安全和弹性在一起(不同的训练师 任何组合对不同动物的能力,包括混合, 一些人没有锁定一个超级特定的培训大师 特定动物的超级特异性能力,仅此而已)。
当然,我的意思是“约翰不能教马小跑和狗 树皮“,而不是”可以教马或狗小跑或吠叫的约翰“
答案 3 :(得分:-2)
是的,您可以将Trainables
,Set<Trainables> completed
和trainingComplete(Trainables t)
移至班级培训师。
这样你就不需要为DogTrainer,HorseTrainer等编写这些代码......等等......
abstract class Trainer<T extends Animal>{
public enum Trainables implements TrainingActions<Animal>{
BARK, BITE, ROLLOVER, FETCH;
}
public Set<Trainables> completed = new HashSet<Trainables>();
public void trainingComplete(Trainables t){completed.add(t);}
}
否则使trainingComplete(Trainables t)摘要,你需要在每个Trainer实现clasees中实现。
abstract class Trainer<T extends Animal>{
public enum Trainables implements TrainingActions<Animal>{
BARK, BITE, ROLLOVER, FETCH;
}
public Set<Trainables> completed = new HashSet<Trainables>();
abstract public void trainingComplete(Trainables t);
}
现在您的DogTrainer和HorseTrainer正在实施trainingComplete(Trainables t)
public class DogTrainer extends Trainer<Dog>{
public void trainingComplete(Trainables t){
completed.add(t);
}
}
public class HorseTrainer extends Trainer<Horse>{
public void trainingComplete(Trainables t){
completed.add(t);
}
}