La solution acceptée est correcte et constitue une solution concrète à votre problème. Cependant, je voudrais poser une solution alternative, plus abstraite.
D'après mon expérience, l'utilisation d'énums pour définir le flux de la logique constitue une odeur de code, car elle est souvent le signe d'une conception de classe médiocre.
J'ai rencontré un exemple concret de ce qui se passe dans le code sur lequel j'ai travaillé l'année dernière. Le développeur d'origine avait créé une classe unique, chargée de la logique d'importation et d'exportation, et basculant entre les deux sur la base d'une énumération. À présent, le code était similaire et comportait un code dupliqué, mais il était suffisamment différent pour rendre le code beaucoup plus difficile à lire et pratiquement impossible à tester. J'ai fini par refactoriser cela en deux classes distinctes, ce qui les a simplifiées et m'a permis de repérer et d'éliminer un certain nombre de bogues non signalés.
Encore une fois, je dois dire que l'utilisation d'énums pour contrôler le flux de la logique est souvent un problème de conception. Dans le cas général, Enums devrait être principalement utilisé pour fournir des valeurs adaptées au type et sécurisées pour le consommateur, lorsque les valeurs possibles sont clairement définies. Ils sont mieux utilisés en tant que propriété (par exemple, en tant qu'ID de colonne dans une table) qu'en tant que mécanisme de contrôle logique.
Considérons le problème présenté dans la question. Je ne connais pas vraiment le contexte ici, ni ce que représente cette énumération. Est-ce que c'est dessiner des cartes? Dessiner des images? Tirer du sang? L'ordre est-il important? Je ne sais pas non plus à quel point la performance est importante. Si les performances ou la mémoire sont essentielles, cette solution ne sera probablement pas celle que vous souhaitez.
Dans tous les cas, considérons l'énumération:
// All possible combinations of One - Eight.
public enum ExampleEnum {
One,
Two,
TwoOne,
Three,
ThreeOne,
ThreeTwo,
ThreeOneTwo
}
Nous avons ici un certain nombre de valeurs enum différentes représentant différents concepts d’entreprise.
Ce que nous pourrions utiliser à la place, ce sont des abstractions pour simplifier les choses.
Considérons l'interface suivante:
public interface IExample
{
void Draw();
}
Nous pouvons alors implémenter cela en tant que classe abstraite:
public abstract class ExampleClassBase : IExample
{
public abstract void Draw();
// other common functionality defined here
}
Nous pouvons avoir une classe concrète pour représenter les dessins un, deux et trois (qui, par souci d'argument, ont une logique différente). Ceux-ci pourraient potentiellement utiliser la classe de base définie ci-dessus, mais je suppose que le concept DrawOne est différent du concept représenté par l'énumération:
public class DrawOne
{
public void Draw()
{
// Drawing logic here
}
}
public class DrawTwo
{
public void Draw()
{
// Drawing two logic here
}
}
public class DrawThree
{
public void Draw()
{
// Drawing three logic here
}
}
Et maintenant, nous avons trois classes distinctes qui peuvent être composées pour fournir la logique aux autres classes.
public class One : ExampleClassBase
{
private DrawOne drawOne;
public One(DrawOne drawOne)
{
this.drawOne = drawOne;
}
public void Draw()
{
this.drawOne.Draw();
}
}
public class TwoOne : ExampleClassBase
{
private DrawOne drawOne;
private DrawTwo drawTwo;
public One(DrawOne drawOne, DrawTwo drawTwo)
{
this.drawOne = drawOne;
this.drawTwo = drawTwo;
}
public void Draw()
{
this.drawOne.Draw();
this.drawTwo.Draw();
}
}
// the other six classes here
Cette approche est beaucoup plus verbeuse. Mais cela a des avantages.
Considérez la classe suivante, qui contient un bogue:
public class ThreeTwoOne : ExampleClassBase
{
private DrawOne drawOne;
private DrawTwo drawTwo;
private DrawThree drawThree;
public One(DrawOne drawOne, DrawTwo drawTwo, DrawThree drawThree)
{
this.drawOne = drawOne;
this.drawTwo = drawTwo;
this.drawThree = drawThree;
}
public void Draw()
{
this.drawOne.Draw();
this.drawTwo.Draw();
}
}
À quel point est-il plus simple de repérer l'appel drawThree.Draw () manquant? Et si l'ordre est important, l'ordre des appels de tirage au sort est également très facile à voir et à suivre.
Inconvénients de cette approche:
- Chacune des huit options présentées nécessite un cours séparé
- Cela utilisera plus de mémoire
- Cela rendra votre code superficiellement plus grand
- Parfois, cette approche n’est pas possible, bien que certaines variations puissent être possibles.
Avantages de cette approche:
- Chacune de ces classes est complètement testable; parce que
- La complexité cyclomatique des méthodes de tirage est faible (et en théorie, je pourrais me moquer des classes DrawOne, DrawTwo ou DrawThree si nécessaire)
- Les méthodes de tirage au sort sont compréhensibles - un développeur n'a pas à se lier le cerveau en travaillant à déterminer ce que la méthode fait.
- Les bugs sont faciles à repérer et difficiles à écrire
- Les classes se composent en classes de plus haut niveau, ce qui signifie qu'il est facile de définir une classe ThreeThreeThree
Considérez cette approche (ou une approche similaire) chaque fois que vous ressentez le besoin de rédiger un code de contrôle logique complexe dans les instructions de cas. Future, vous serez heureux de l'avoir fait.