“设置”特定枚举类型但具有泛型

时间:2013-10-11 03:29:47

标签: java generics enums

假设我有一个抽象类

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和泛型的奇怪组合。

这可能吗?

4 个答案:

答案 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.TrainablesTrainingActions<Dog>
  • 您的HorseTrainer.TrainablesTrainingActions<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)

是的,您可以将TrainablesSet<Trainables> completedtrainingComplete(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);
     }
 }