5

Continuando su domande precedenti (here e here), ho implementato un modello di comando di base, creato le mie classi di comando e codificato su un'interfaccia, quindi quando viene usato un comando, per chiamare il Metodo execute().problemi nel rendere il polimorfismo sconfiggere quelle istruzioni switch/case

Tuttavia, mi sto ancora ritrovando incapace di scuotere quelle dichiarazioni di caso: sto leggendo ogni personaggio da una stringa principale/decisione, che è composta da caratteri casuali, ripetuti A, B, C o D, e poi I recupera l'implementazione relativa del comando da una mappa e chiama il suo metodo di esecuzione.

Il mio progetto era come questo:

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); 

Ma, poi quando ho letto ogni istruzione, ancora una volta devo ricorrere a caso dichiarazioni:

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;} 

Ovviamente, da qualche parte lungo la strada sono riuscito per sconfiggere il vantaggio del polimorfismo contro le dichiarazioni del caso.

Potrebbe essere il tipo di struttura dati che ho selezionato per memorizzare i miei comandi? Può benissimo essere una struttura dati permanente da cui estrarre solo quei comandi.

Un'altra cosa che mi viene in mente è la denominazione chiave/valore che ho usato nella mia mappa. Il modo in cui ho provato a collegare concettualmente ogni comando memorizzato alle istruzioni associate? cioè l'implementazione del comando "A", è memorizzata sulla mappa con il tasto "A" in modo che possa corrispondere all'istruzione corrispondente "A"? Questo mi sembra un po 'improbabile.

Qualsiasi suggerimento o ulteriore consiglio sulla mia prossima mossa per rimuovere quelle dichiarazioni di caso una volta per tutte sarebbe molto apprezzato. Molte grazie in anticipo

risposta

14

I può essere manca qualcosa qui, ma anziché l'istruzione switch, cosa c'è di sbagliato con

((Command)myMap.get(instructionFromString)).execute(); 

Se instructionFromString è un char, il convertito in una String prima di fare la mappa di ricerca, altrimenti utilizzare le chiavi Character nella mappa.

Inoltre, se si utilizza una mappa generica Java 5, è possibile rimuovere il cast in Command. Una versione ripulita sarebbe:

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()); 

seguito da:

char instructionFromString = .... 
myMap.get(instructionFromString).execute(); 
+0

@skaffman: Siamo spiacenti. Sono riuscito in qualche modo a leggere il codice di esempio, ma ho perso il testo sopra e sotto di esso. – Dirk

+0

+1 per risposta I "citare" ed espandere. – KLE

+0

@skaffman: Grazie, abbastanza elegante asnwer. Non posso credere di averlo perso! – denchr

0

Con una semplice mappa, le cose possono diventare cattivi dal momento che si sta utilizzando di nuovo la stessa istanza di CommandA.

Un buon modo per incapsulare questo tipo di comportamento sarebbe un fabbrica:

public class CommandFactory 
{ 
    public Command CreateCommand(String instruction) 
    { 
     if (instruction.equals("A")) 
      return new CommandA(); 
     else if ... 
    } 
} 

Un altro modo sarebbe la prototype pattern (aka modello clone), che consente una gestione più flessibile dei molteplici differenti tipi (comandi per questo):

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(); 
    } 
} 

Come forse avrete notato, si dovrà implementare il comportamento clone in Commands, che può richiedere molto tempo.

0

Mi piace la risposta di Skaffman. Voglio solo aggiungerne un altro:

Per assegnare un nome ai comandi, è possibile utilizzare uno schema più semplice. Ad esempio, è possibile utilizzare il nome del comando, come caso predefinito.

  • Nel caso generale, tanto meno da digitare. Elimina gli errori.
  • Quando il nome è diverso, si configura ancora la mappa per questo caso specifico.

Molte tecnologie sono disponibili per mettere in relazione il nome e il comando. Esempi:

  • Annotazioni per la classe, che specifica il nome del comando (con un valore predefinito uguale al nome della classe).
  • La configurazione Spring è già una grande mappa e fornisce direttamente l'oggetto corrispondente, con molti altri servizi disponibili lungo il percorso.
  • Anche le enumerazioni Java associano un nome a un oggetto. Inoltre, ti permettono di avere il completamento e il controllo in fase di compilazione nel tuo IDE, insieme a "ricerca di riferimento" e altre chicche.
+0

@KLE: Grazie! Abbastanza utili suggerimenti anche lì. – denchr

Problemi correlati