1

Une structure enum déclarée dans sa propre classe est une variable membre de la classe de logique métier. Cette énumération représente essentiellement l'état de cette autre classe.Refactoring et suppression des instructions de requête lors d'un encerclement sur une structure enum

Bien que j'ai réexaminé le problème plusieurs fois, le remplacement ou l'élimination de ces déclarations de cas s'avère très frustrant pour moi.

Plusieurs méthodes de logique métier parcourent simplement l'énumération et modifient l'état de cette classe en affectant une autre valeur de la même énumération et d'autres propriétés.

public enum MyEnum{ A,B,C,D } 

La classe logique métier a cette ENUM en tant que membre:

public class BusinessLogic { 

    private MyEnum CurrentSelection; 
    private int propertyX; 
    private int propertyY; 

    public void operation1(){ 
     switch(CurrentSelection){ 
     case A: {alter propertyX this way; break;} 
     case B: {alter propertyY this way; break;} 
     case C: {alter propertyX that way; break;} 
     case D: {alter propertyY that way; break;} 
     } 

    } 

    public void operation2(){ 
     switch(CurrentSelection){ 
     case A: {CurrentSelection=MyEnum.B; break;} 
     case B: {CurrentSelection=MyEnum.C; break;} 
     ....etc 
     } 
    } 

    public void operation3(){ 
     switch(CurrentSelection){ 
     case A: {CurrentSelection=MyEnum.D; break;} 
     case B: {CurrentSelection=MyEnum.A; break;} 
     ....etc 
     } 
    } 
} 

Une autre classe de client instancier la classe de logique métier, paraphant ses propriétés, puis en utilisant ses méthodes de fonctionnement. Ce que j'ai fait avec succès (avec l'aide de SO) encapsule les méthodes d'opération dans une structure de modèle de commande afin que je puisse appeler les opérations sans toutes les déclarations de cas. (here).

Je suppose que mon problème est de savoir comment encapsuler les instructions case dans ma classe de logique métier. Je soupçonne que j'aurais besoin de polymorphisme et des structures de données appropriées.

Les experts en refactoring suggèrent que chaque déclaration de cas soit une implémentation d'une interface commune. Mais si j'ai 3 méthodes d'itération sur une énumération de 4 membres, cela signifie que j'ai probablement besoin de 3 interfaces avec 4 implémentations chacune, ce qui me donne 12 classes (plus 3 interfaces). Ce ne serait pas une surcharge de classe? La logique fonctionne correctement avec ces 3 méthodes telles qu'elles sont, mais le problème sont les instructions de commutation/cas répétées.

Existe-t-il un moyen de refactoriser ces instructions de commutation, mais éviter une myriade d'autres classes dans le nom du polymorphisme? Serait-il possible de factoriser la partie itérative sur l'enum? Ou juste les cas (où la logique est) devraient être refactorisés?


En premier lieu j'ai enlevé ces méthodes complètement que je les avoir à mettre en œuvre une interface simple:

public interface Command { 
    void execute(); 
} 

Ainsi, sa méthode de fonctionnement mis en œuvre l'interface de commande:

public class Operation1 implements Command { 

    private void doOperation1(){ 
     switch(CurrentSelection){ 
      ..all the cases here 
     }  
    } 

    public void execute() { 
     doOperation1(); 
    } 

} 

Comme je l'ai voyez ça, ça va m'acheter un cours de logique d'entreprise plus propre, mais la piste des cas de switch restera, non?

Répondre

1

vous pouvez inclure les trois méthodes dans une interface et ont différentes implémentations de cette interface (un pour chaque ENUM), et ont ce délégué de classe buisness les appels ..

aussi pour changer l'état, est le retour valeur de l'opération soit cette interface commune de sorte que lors de l'appel de ces méthodes, la classe invoquante puisse renvoyer l'objet approprié pour l'état suivant.

+0

Merci pour la réponse. Oui, mais ces implémentations individuelles ne porteraient-elles pas toujours les instructions switch/case? Je nettoierais la logique métier et les classes client, mais les nouvelles classes implémentant chacune des 3 interfaces conserveraient les cas de commutation. Est-ce que mon raisonnement est correct, ou peut-être que cela ne vous ennuierait pas d'en dire un peu plus? – denchr

+0

Vous pourriez avoir accès à la classe différente par l'énumération elle-même - ie l'enum implémente l'interface, ou quelque chose de similaire. vous n'avez donc pas à l'allumer du tout. Ceci est similaire au modèle de commande. – aperkins

1

Pour des détails sur mon commentaire, et l'approche de ce que je pense rmn parle, vous pouvez faire ce qui suit:

public interface MyInterface { 
    operation1(property); 
    operation2(property); 
    operation3(property); 
} 

public enum MyEnum implements MyInterface { 
    A { 
     operation1(property) { 
      //Do Stuff 
     } 
     operation2(property) { 
      //Do Stuff 
     } 
     operation3(property) { 
      //Do Stuff 
     } 
    }, 
    B { 
     operation1(property) { 
      //Do Stuff 
     } 
     operation2(property) { 
      //Do Stuff 
     } 
     operation3(property) { 
      //Do Stuff 
     } 
    }, 
    C { 
     operation1(property) { 
      //Do Stuff 
     } 
     operation2(property) { 
      //Do Stuff 
     } 
     operation3(property) { 
      //Do Stuff 
     } 
    }, 
    D { 
     operation1(property) { 
      //Do Stuff 
     } 
     operation2(property) { 
      //Do Stuff 
     } 
     operation3(property) { 
      //Do Stuff 
     } 
    } 
} 

Cela fait en sorte que vous avez un modèle de commande - à savoir quelque chose qui fait le travail pour vous en fonction de l'élément différent sélectionné. Il est également similaire à un modèle d'état, bien que l'accent soit mis ici sur l'exécution plutôt que sur les données ou l'état des données.

Espérons que cela aide.

+2

c'est exactement ce que j'ai suggéré, il suffit que les opérations retournent MyInterface, de sorte que vous puissiez changer l'état lors de l'appel d'une fonction. quelque chose comme MyInterface operation1 (propriété) { // faire des choses, ne pas changer d'état retourner ceci; } et: MyInterface operation2 (propriété) { // faire des tâches et modifier l'état return A(); } puis u peut l'utiliser comme: currstate = currstate.operation1() et vous avez terminé – rmn

+0

Merci, je vais essayer d'intégrer que la logique du problème. J'avoue que je ne peux pas voir tout de suite comment cela pourrait aider, car les méthodes d'opération font partie du comportement de l'objet de logique métier. Je dois encore déléguer de cet objet à la structure enum droite? - Excuses si ma question est un peu confuse. J'aurai besoin d'expérimenter avec votre suggestion, tirer quelques conclusions et ensuite formuler une question plus précise. – denchr

+0

@rmn Je sais que c'est ce que vous aviez suggéré, c'est pourquoi je vous ai upvoted. Je pensais juste qu'il aurait besoin d'un meilleur exemple, et je voulais le donner, ce que ces boîtes de commentaires ne permettent pas vraiment. – aperkins

0

Comme vous l'avez peut-être deviné à partir des autres réponses, il s'agit d'un problème commun qui a été codifié en un refactoring par Martin Fowler. Jetez un oeil à la refactorisation Replace Conditional with Polymorphism. Il existe également un refactoring codifié similaire par Joshua Kerievsky (Replace Conditional with Strategy).

+0

Oui, c'est ce que je voulais dire en disant: "Les experts en refactoring suggèrent que chaque déclaration de cas devrait être une implémentation d'une interface commune" dans mon post original. Cependant, dans celui-ci, ce n'était pas simple pour moi. – denchr