J'essaie d'écrire une servlet qui effectue une tâche en fonction de la valeur "action" transmise en entrée.
Voici l'exemple dont
public class SampleClass extends HttpServlet {
public static void action1() throws Exception{
//Do some actions
}
public static void action2() throws Exception{
//Do some actions
}
//And goes on till action9
public void doPost(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException {
String action = req.getParameter("action");
/**
* I find it difficult in the following ways
* 1. Too lengthy - was not comfortable to read
* 2. Makes me fear that action1 would run quicker as it was in the top
* and action9 would run with a bit delay - as it would cross check with all the above if & else if conditions
*/
if("action1".equals(action)) {
//do some 10 lines of action
} else if("action2".equals(action)) {
//do some action
} else if("action3".equals(action)) {
//do some action
} else if("action4".equals(action)) {
//do some action
} else if("action5".equals(action)) {
//do some action
} else if("action6".equals(action)) {
//do some action
} else if("action7".equals(action)) {
//do some action
} else if("action8".equals(action)) {
//do some action
} else if("action9".equals(action)) {
//do some action
}
/**
* So, the next approach i tried it with switch
* 1. Added each action as method and called those methods from the swith case statements
*/
switch(action) {
case "action1": action1();
break;
case "action2": action2();
break;
case "action3": action3();
break;
case "action4": action4();
break;
case "action5": action5();
break;
case "action6": action6();
break;
case "action7": action7();
break;
case "action8": action8();
break;
case "action9": action9();
break;
default:
break;
}
/**
* Still was not comfortable since i am doing un-necessary checks in one way or the other
* So tried with [reflection][1] by invoking the action methods
*/
Map<String, Method> methodMap = new HashMap<String, Method>();
methodMap.put("action1", SampleClass.class.getMethod("action1"));
methodMap.put("action2", SampleClass.class.getMethod("action2"));
methodMap.get(action).invoke(null);
/**
* But i am afraid of the following things while using reflection
* 1. One is Security (Could any variable or methods despite its access specifier) - is reflection advised to use here?
* 2. Reflection takes too much time than simple if else
*/
}
}
Tout ce dont j'ai besoin est d'échapper à trop de contrôles if / else-if dans mon code pour une meilleure lisibilité et une meilleure maintenance du code. Donc essayé pour d'autres alternatives comme
1. changer de boîtier - il fait encore trop de vérifications avant de faire mon action
2. réflexion
i] une chose principale est la sécurité - qui me permet d'accéder même aux variables et méthodes de la classe malgré son spécificateur d'accès - je ne suis pas sûr que je pourrais l'utiliser dans mon code
ii] et l'autre est que cela prend plus de temps que les simples vérifications if / else-if
Existe-t-il une meilleure approche ou une meilleure conception que quelqu'un pourrait suggérer pour organiser le code ci-dessus d'une meilleure manière?
ÉDITÉ
J'ai ajouté la réponse pour l'extrait ci-dessus en tenant compte de la réponse ci-dessous .
Mais encore, les classes suivantes "ExecutorA" et "ExecutorB" ne font que quelques lignes de code. Est-ce une bonne pratique de les ajouter en tant que classe plutôt que de les ajouter en tant que méthode? Veuillez conseiller à cet égard.
la source
Réponses:
Sur la base de la réponse précédente, Java permet aux enums d'avoir des propriétés afin que vous puissiez définir un modèle de stratégie, quelque chose comme
Alors votre
Executor
(stratégie) seraitEt tous vos if / else dans votre
doPost
méthode deviennent quelque chose commeDe cette façon, vous pouvez même utiliser lambdas pour les exécuteurs dans les énumérations.
la source
Executor
est (ou peut être) une interface fonctionnelle.Au lieu d'utiliser la réflexion, utilisez une interface dédiée.
c'est-à-dire au lieu de:
Utilisation
Implémente chacun d'eux pour chaque action puis:
Bien sûr, cette solution n'est pas la plus légère, vous n'aurez donc pas besoin d'aller jusqu'à cette longueur.
la source
ProcessAction
au lieu deActionProcess
ça, alors ...?Utilisez le modèle de commande , cela nécessitera une interface de commande quelque chose comme ceci:
Si la construction
Actions
est légère et bon marché, utilisez une méthode d'usine. Chargez les noms de classe à partir d'un fichier de propriétés qui mappeactionName=className
et utilisez une méthode d'usine simple pour construire les actions à exécuter.Si les actions sont coûteuses à construire, utilisez un pool, tel qu'un HashMap ; cependant, dans la plupart des cas, je dirais que cela pourrait être évité en vertu du principe de responsabilité unique en déléguant l' élément coûteux à un pool de ressources communes préconstruit plutôt qu'aux commandes elles-mêmes.
Ceux-ci peuvent ensuite être exécutés avec
Il s'agit d'une approche très robuste et découplée qui applique les principes SRP, LSP et ISP des principes SOLID . Les nouvelles commandes ne modifient pas le code du mappeur de commandes. Les commandes sont simples à implémenter. Ils peuvent être simplement ajoutés au fichier de projet et de propriétés. Les commandes doivent être réentrantes et cela le rend très performant.
la source
Vous pouvez utiliser l'objet basé sur l'énumération pour réduire le besoin de coder en dur les valeurs de chaîne. Cela vous fera gagner du temps et rendra le code beaucoup plus agréable à lire et à étendre à l'avenir.
la source
Le modèle de méthode d'usine est ce que je recherche si vous recherchez une conception évolutive et moins maintenable.
Le modèle de méthode d'usine définit une interface pour créer un objet, mais laisse la sous-classe décider de la classe à instancier. La méthode d'usine permet à une classe de reporter l'instanciation à la sous-classe.
action1, action2 ........ actionN implémentation concrète avec la méthode doStuff implémentant la chose à faire.
Il suffit d'appeler
Donc, à l'avenir, si plus d'actions sont introduites, il vous suffit d'ajouter une classe concrète.
la source
En référence à @J. Pichardo répond que j'écris la modification de l'extrait ci-dessus comme suit
la source