Estoy tratando de escribir un servlet que realiza una tarea basada en el valor de "acción" que se le pasó como entrada.
Aquí está la muestra de que
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
*/
}
}
Todo lo que necesito es escapar de demasiados controles if / else-if en mi código para una mejor legibilidad y un mejor mantenimiento del código. Intenté otras alternativas como
1. cambio de mayúsculas y minúsculas : todavía hace demasiadas comprobaciones antes de realizar mi acción
2. reflexión
i] una cosa principal es la seguridad, que me permite acceder incluso a las variables y métodos dentro de la clase a pesar de su especificador de acceso, no estoy seguro de si podría usarlo en mi código
ii] y el otro es que lleva más tiempo que las simples comprobaciones if / else-if
¿Hay algún mejor enfoque o mejor diseño que alguien pueda sugerir para organizar el código anterior de una mejor manera?
EDITADO
He agregado la respuesta para el fragmento anterior considerando la respuesta a continuación .
Pero aún así, las siguientes clases "EjecutorA" y "EjecutorB" solo hacen unas pocas líneas de código. ¿Es una buena práctica agregarlos como clase que agregarlo como método? Por favor avise al respecto.
fuente
Respuestas:
Según la respuesta anterior, Java permite que las enumeraciones tengan propiedades para que pueda definir un patrón de estrategia, algo así como
Entonces su
Executor
(Estrategia) seríaY todos tus if / else en tu
doPost
método se convierten en algo asíDe esta manera, incluso podría usar lambdas para los ejecutores en las enumeraciones.
fuente
Executor
es (o puede ser) una interfaz funcional.En lugar de usar la reflexión, use una interfaz dedicada.
es decir, en lugar de:
Utilizar
Implementa cada uno de ellos para cada acción y luego:
Por supuesto, esta solución no es la más ligera, por lo que es posible que no necesite llegar a esa longitud.
fuente
ProcessAction
lugar de ¿ActionProcess
es así que ...?Use el patrón de comando , esto requerirá una interfaz de comando similar a esta:
Si
Actions
son livianos y económicos de construir, use un Método de fábrica. Cargue los nombres de clase de un archivo de propiedades que asignaactionName=className
y use un método de fábrica simple para construir las acciones para la ejecución.Si las acciones son caras de construir, utilice un grupo, como un HashMap ; sin embargo, en la mayoría de los casos, sugeriría que esto podría evitarse bajo el Principio de responsabilidad única que delega el elemento costoso en algún grupo de recursos comunes preconstruido en lugar de los comandos en sí.
Estos se pueden ejecutar con
Este es un enfoque muy robusto y desacoplado que aplica SRP, LSP e ISP de los principios SOLID . Los nuevos comandos no cambian el código del mapeador de comandos. Los comandos son simples de implementar. Se pueden agregar al proyecto y al archivo de propiedades. Los comandos deben ser reentrantes y esto lo hace muy eficaz.
fuente
Puede utilizar el objeto basado en enumeración para reducir la necesidad de codificar los valores de cadena. Le ahorrará algo de tiempo y hará que el código sea mucho más fácil de leer y extender en el futuro.
fuente
El patrón Método de fábrica es lo que busco si buscas un diseño escalable y menos mantenible.
El patrón Método de fábrica define una interfaz para crear un objeto, pero permite que la subclase decida qué clase instanciar. El Método de Fábrica permite que una clase difiera la instanciación a la subclase
action1, action2 ........ actionN implementación concreta con el método doStuff implementando cosas que hacer.
Solo llama
Entonces, en el futuro, si se introducen más acciones, solo necesita agregar una clase concreta.
fuente
Con referencia a @J. Respuesta de Pichardo, estoy escribiendo la modificación del fragmento anterior como el siguiente
fuente