“Sets” d’un type enum particulier mais avec des génériques

Disons que j’ai un cours abstrait

public abstract class Trainer{} 

J’ai des formateurs spécifiques comme:

 public DogTrainer extends Trainer{} public HorseTrainer extends Trainer{} 

Chacun de ces “dresseurs” dispose d’un ensemble de trucs fixes qu’il est possible d’apprendre à l’animal, pour lequel j’aimerais utiliser Enums. J’ai donc une interface:

 public interface TrainingActions{} 

et dans chacun des formateurs, j’ai un Enum qui implémente cette interface. Alors:

 public DogTrainer extends Trainer{ public enum Trainables implements TrainingActions{ BARK, BITE, ROLLOVER, FETCH; } } public HorseTrainer extends Trainer{ public enum Trainables implements TrainingActions{ JUMP, TROT, REARUP; } } 

Maintenant, dans chacune des classes du formateur, je voudrais une méthode “trainingComplete” qui prenne un des Enums comme entrée et l’enregistre dans un ensemble. Alors

 public DogTrainer extends Trainer{ public enum Trainables implements TrainingActions{ BARK, BITE, ROLLOVER, FETCH; } public Set completed = new HashSet(); public void trainingComplete(Trainables t){completed.add(t);} } 

Cependant, au lieu de définir l’ensemble ‘terminé’ dans chacun des Formateurs spécifiques et la méthode ‘trainingComplete’ dans chacun des formateurs, j’aimerais que quelque chose de la classe parent ‘Trainers’ puisse être appliqué au type Enum … C’est donc une étrange combinaison de Enums et de génériques.

Est-ce possible?

Pour spécifier un lié à une interface et qu’il s’agisse d’une énumération, vous avez besoin d’une intersection générique, qui ressemble à:

 class MyClass & SomeInterface> {} 

Notez que lorsque vous intersectez une classe et une ou plusieurs interfaces, la classe doit apparaître avant la ou les interfaces.

Dans ce cas, les génériques de Kung Fu que vous voulez sont d’un niveau plus compliqué, car l’interface de l’énumération TrainingActions doit elle-même renvoyer au type d’animal.

 class Trainer & TrainingActions> {} 

Un exemple de travail complet, basé sur votre code posté, qui comstack est:

 public class Animal {} public interface TrainingActions {} /** * A trainer that can teach an animal a suitable set of sortingcks * @param  The type of Animal * @param  The enum of TrainingActions that can be taught to the specified Animal */ public abstract class Trainer & TrainingActions> { private Set completed = new HashSet(); public void trainingComplete(T t) { completed.add(t); } } public class Dog extends Animal {}; public class DogTrainer extends Trainer { public enum Trainables implements TrainingActions { BARK, BITE, ROLLOVER, FETCH; } } 

Mais je ferais un pas de plus en définissant plusieurs énumérations de TrainingActions dans la classe de l’ Animal auquel elles s’appliquent:

 public class Dog extends Animal { public enum BasicTrainables implements TrainingActions { SIT, COME, STAY, HEEL; } public enum IntermediateTrainables implements TrainingActions { BARK, BITE, ROLLOVER, FETCH; } public enum AdvacedTrainables implements TrainingActions { SNIFF_DRUGS, FIND_PERSON, ATTACK, GUARD; } }; public class PuppyTrainer extends Trainer {} public class ObedienceTrainer extends Trainer {} public class PoliceTrainer extends Trainer {} 

En dépit de l’parsing de conception, je pense que la réponse à votre situation (la plus proche de votre conception déjà créée) est la suivante:

  • votre DogTrainer.Trainables est TrainingActions
  • votre HorseTrainer.Trainables est TrainingActions

En général, vos TrainingActions sont déjà un TrainingActions

Ainsi, vous pouvez simplement fournir Set> completed , car vous avez déjà vos informations sur les animaux dans T :

 abstract class Trainer { Set> completed = new HashSet>(); public void add(TrainingActions t ) { completed.add( t ); } } 

Et vous avez exactement ce que vous voulez.

Usage:

 DogTrainer tr = new DogTrainer(); tr.add( DogTrainer.Trainables.BITE ); 

Si vous êtes sûr de vouloir appliquer un Enum à votre interface:

 public  & TrainingActions> void add( E t ) { completed.add( t ); } 

Je posterai cela pour examen ultérieur, même s’il y a déjà une réponse acceptée

Si vous lisez cette question, envisagez d’utiliser davantage d’éléments couplés, avec l’agrégation, etc. au lieu d’une hiérarchie de types et de génériques très spécifiques et complexes.

Avec une simple agrégation, vous pouvez atteindre au moins le même type et la même sécurité logique, mais une conception couplée souple. Comme je l’ai mentionné dans les commentaires:

Mieux vaut mieux avoir plus de collections, d’agrégations, etc. pour assurer la sécurité et l’élasticité des types (différents entraîneurs avec des capacités différentes pour des animaux différents dans toutes les combinaisons, y compris le mixage, ne pas verrouiller une personne de l’animal spécifique et rien de plus ).

Bien sûr, je veux dire un “Jean qui peut apprendre à cheval à trotter et un chien à aboyer”, pas “Jean qui peut apprendre à cheval ou à un chien à trotter ou à aboyer”

Oui, vous pouvez déplacer vos Trainables , Set completed et trainingComplete(Trainables t) vers le formateur de la classe.

De cette façon, vous n’avez pas besoin d’écrire ces codes chaque DogTrainer, HorseTrainer .. et ainsi de suite …

  abstract class Trainer{ public enum Trainables implements TrainingActions{ BARK, BITE, ROLLOVER, FETCH; } public Set completed = new HashSet(); public void trainingComplete(Trainables t){completed.add(t);} } 

Autrement, faites en sorte que trainingComplete (Trainables t) soit abstrait et que vous ayez à implémenter dans chaque implémentation du formateur des clases.

 abstract class Trainer{ public enum Trainables implements TrainingActions{ BARK, BITE, ROLLOVER, FETCH; } public Set completed = new HashSet(); abstract public void trainingComplete(Trainables t); } 

Maintenant, votre DogTrainer et votre HorseTrainer implémentent trainingComplete(Trainables t)

  public class DogTrainer extends Trainer{ public void trainingComplete(Trainables t){ completed.add(t); } } public class HorseTrainer extends Trainer{ public void trainingComplete(Trainables t){ completed.add(t); } }