java - republica - problemas para hacer que el polimorfismo derrote esas declaraciones de cambio/caso
objetivo de la declaracion de cambio (3)
Continuando con las preguntas anteriores ( aquí y aquí ), implementé un patrón de comando básico, creé mis clases de comando y codifiqué a una interfaz, de modo que cuando se usa cualquier comando, llame al método execute()
.
Sin embargo, todavía me encuentro incapaz de sacudir esas declaraciones de casos: estoy leyendo cada carácter de una cadena maestra / decisión, que está formada por caracteres aleatorios que se repiten A, B, C o D, y luego recupero la implementación relacionada del comando desde un mapa y llamar a su método de ejecución.
Mi diseño fue así:
public interface Command {
void execute();
}
public class CommandA implements Command{
//implements execute() method
}
private Map myMap= new HashMap();
myMap.put("A", new CommandA);
myMap.put("B", new CommandB);
myMap.put("C", new CommandC);
myMap.put("D", new CommandD);
Pero luego, cuando leo cada instrucción, de nuevo tengo que recurrir a declaraciones de casos:
switch(instructionFromString){
case ''A'':{myMap.get("A").execute(); break;}
case ''B'':{myMap.get("B").execute(); break;}
case ''C'':{myMap.get("C").execute(); break;}
case ''D'':{myMap.get("D").execute(); break;}
Obviamente, en algún punto del camino logré vencer la ventaja del polimorfismo frente a las declaraciones de casos.
¿Podría ser el tipo de estructura de datos que seleccioné para almacenar mis comandos? Puede ser una estructura de datos permanente para extraer esos comandos.
Otra cosa que me viene a la mente es el nombre clave / valor que utilicé en mi mapa. ¿De qué manera traté de vincular conceptualmente cada comando almacenado con su instrucción asociada? es decir, la implementación del comando "A", se almacena en el mapa con la tecla "A" para que coincida con la instrucción "A" correspondiente. Sin embargo, eso me parece un poco improbable.
Cualquier sugerencia o consejo adicional sobre mi próximo movimiento para eliminar esas declaraciones de caso de una vez por todas sería muy apreciada. Muchas gracias de antemano
Con un mapa simple, las cosas pueden ponerse feas ya que estás usando la misma instancia de CommandA
una vez más.
Una buena forma de encapsular este tipo de comportamiento sería una fábrica :
public class CommandFactory
{
public Command CreateCommand(String instruction)
{
if (instruction.equals("A"))
return new CommandA();
else if ...
}
}
Otra forma sería el patrón prototipo (también conocido como patrón de clonación) que permite un manejo más flexible de múltiples tipos diferentes (comandos para el caso):
public class CommandFactory
{
private Map<String, Command> commands = new HashMap<String, Command>();
public void RegisterCommand(String instruction, Command commandTemplate)
{
commands.put(instruction, commandTemplate);
}
public Command CreateCommand(String instruction)
{
return commands.get(instruction).clone();
}
}
Como habrás notado, deberás implementar el comportamiento de clonación en Commands
, lo que puede llevar mucho tiempo.
Me gusta la respuesta de Skaffman. Solo quiero agregar un poco más:
Para nombrar sus comandos, puede usar un patrón más simple. Por ejemplo, podría usar el nombre del comando como caso predeterminado.
- En el caso general, mucho menos para escribir. Elimina errores.
- Cuando el nombre es diferente, aún configura el mapa para este caso específico.
Muchas tecnologías están disponibles para relacionar el nombre y el comando. Ejemplos:
- Anotaciones para la clase, que especifica el nombre del comando (con un valor predeterminado que es igual al nombre de la clase).
- La configuración de primavera ya es un gran mapa, y entrega directamente el objeto correspondiente, con muchos más servicios disponibles en el camino.
- Las enumeraciones Java también asocian naturalmente un nombre con un objeto. Además, le permiten completar y verificar el tiempo de compilación en su IDE, junto con la "búsqueda de referencia" y otros artículos.
Me puede estar perdiendo algo aquí, pero en lugar de la declaración de switch
, ¿qué hay de malo en
((Command)myMap.get(instructionFromString)).execute();
Si instructionFromString es un char
, conviértalo en un String
antes de hacer la búsqueda del mapa, de lo contrario use las teclas de Character
en su mapa.
Además, si usa un mapa genérico Java 5, puede eliminar el lanzamiento a Command
. Una versión limpia sería:
private Map<Character, Command> myMap = new HashMap<Character, Command>();
myMap.put(''A'', new CommandA());
myMap.put(''B'', new CommandB());
myMap.put(''C'', new CommandC());
myMap.put(''D'', new CommandD());
seguido por:
char instructionFromString = ....
myMap.get(instructionFromString).execute();