[Command Pattern] un chiarimento

di il
10 risposte

[Command Pattern] un chiarimento

Buongiorno ,

Ho scoperto questo Pattern che mi ha suggerito Migliorabile che ringrazio;
ma ho alcuni dubbi che non mi permettono di andare avanti.
Chiedo per cortesia di illuminarmi Ho creato un esempio per semplificare al massimo il problema.
Nell'esempio creo un comando "/open" per aprire una porta dopo averlo digitato nella console in questo modo --> /open Door.
Il comando home.open fa uso di una costante e non prende nessuna variabile ad esempio param che in questo caso mi farebbe comodo.

/open è il comando
Door è il parametro


Come passo il parametro dentro home.open() senza usare una variabile locale dentro main?
Se utilizzassi una variabile dentro main , sarei costretto a creare ogni comando dentro main, perchè diversamente non saprei come
passargliela

Grazie per qualsiasi info

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {

        /* Creo una classe esempio di nome Home */
        Home home               = new Home();
        /* Leggo i comandi da console */
        BufferedReader console  = new BufferedReader(new InputStreamReader(System.in));
        
        /* inizializzo il Factory E aggiungo un nuovo comando "/open" */
        final CommandFactory cf = CommandFactory.init(home);
        cf.addCommand("/open", () -> home.open("Door") );   // <--- qui dovrebbe prendere un parametro , ora c'e solo una costante stringa
        
        /* Attendo l'immissione di un comando */        
        System.out.print("Enter command:->");
        String input = console.readLine();
       
        /* Verifico che sia un comando . Deve iniziare con "/" */
        if (input.startsWith("/")){
            String[] parsing = input.split(" ");
            String cmd       = parsing[0].replace("/","");
            String param    = parsing[1];
      
        /* Eseguo il comando */    
            cf.executeCommand("/open");
        }
    }
}
Classe Home

public class Home {
     public void open(String door){
        System.out.println ("Open " + door);
    }
}

incollo per comodità: https://en.wikipedia.org/wiki/Command_patter

10 Risposte

  • Re: [Command Pattern] un chiarimento

    Cyrano ha scritto:


    cf.addCommand("/open", () -> home.open("Door") ); // <--- qui dovrebbe prendere un parametro , ora c'e solo una costante stringa
    Nel Command Pattern, generalmente le "nozioni" utili per poter usare una certa altra entità, sono nella implementazione del Command. Se non deve essere così, come stai appunto chiedendo, allora il fatto di poter passare un argomento deve essere già noto a livello della interfaccia (nel metodo) del Command. Questo però ha senso se tutti (o quasi) i comandi hanno appunto bisogno di ricevere un argomento (o più) e possibilmente dello stesso tipo.
    Se un comando avesse bisogno di un String, un altro di due int, un altro di un array ..... allora devi rivalutare un po' ...
  • Re: [Command Pattern] un chiarimento

    Confermo che tutti i comandi sono accompagnati sulla riga di comando(console) da uno o più parametri dello stesso tipo (String)
  • Re: [Command Pattern] un chiarimento

    Cyrano ha scritto:


    Confermo che tutti i comandi sono accompagnati sulla riga di comando(console) da uno o più argomenti dello stesso tipo (String)
    public interface MyCommand {
        void execute(String... args);
    }
    MyCommand/execute come li hai chiamati tu ... non so.
  • Re: [Command Pattern] un chiarimento

    Ho aggiornato :

    Interfaccia come hai suggerito
    
    @FunctionalInterface
    public interface Command {
    	public void apply(String param);
    }
    
    L'executeCommand
    
    	public void executeCommand(String name,String param) {
    		if (commands.containsKey(name)) {
    			commands.get(name).apply(param);
    		}
    	}
    
    Ora mi da errore qui dicendo: Tipo incompatibile
    
    cf.addCommand("/open", () -> { home.open("Door");  }); 
    
    Quello che continua a confondermi è il "legame" tra quel home.open ed il Factory.
    Il metodo open passa una stringa ma il compilatore continua a protestare

    nota:
    Ho scoperto che se trasformo quel lampda in una inner class finalmente scopro dove è implementato l'ovveride di apply().Era tutto "nascosto" ( me lo ha mostrato netBeans)
  • Re: [Command Pattern] un chiarimento

    Ecco perchè!:
    cf.addCommand("/open", (String) -> { home.open("Door"); });
    e pensare che sono partito da uno switch

    Quel "door" no capisco che strada fa
  • Re: [Command Pattern] un chiarimento

    Cyrano ha scritto:


    
    cf.addCommand("/open", () -> { home.open("Door");  }); 
    
    Se il metodo del Command ha un parametro String ...... allora la lambda avrà un parametro String (deducibile come tipo per inferenza).
    
    cf.addCommand("/open", arg -> { home.open(arg);  }); 
    
  • Re: [Command Pattern] un chiarimento

    Ok , ancora una cosa per cortesia


    "door" passa in open(String door)
    
    public class Home {
     
        public void open(String door){
            System.out.println ("Open " + door);
        }
    }
    
    Il param invece passando per una interfaccia apply() fa ovveride e sovrascrive la stringa door?
  • Re: [Command Pattern] un chiarimento

    Cyrano ha scritto:


    Il param invece passando per una interfaccia apply() fa ovveride e sovrascrive la stringa door?
    Ma che vuol dire!??

    --------------

    Quando fai:

    cf.addCommand("/open", arg -> { home.open(arg); });

    Il addCommand immagino che sia

    public void addCommand(String name, Command cmd)

    Il compilatore "vede" che Command è tecnicamente una functional interface, il suo SAM (Single Abstract Method) riceve un String, pertanto accetta la lambda deducendo quindi per inferenza che arg è di tipo String. E nel body il open riceve un String, quindi coerente, ok.


    Quando farai la esecuzione es.

    cf.executeCommand("/open", valoreRicevutoInInput);

    Immagino che executeCommand andrà a fare un "lookup" del Command per il nome. Ottenuto l'oggetto Command, invocherà esplicitamente il apply passando il valore del secondo parametro di executeCommand che è appunto l'argomento ricevuto in input.

    Stop, tutto qui.
  • Re: [Command Pattern] un chiarimento

    Sto leggendo anche sulle lambda
    Sta volta vi ho rotto per un bel pò , vi dovrei spedire del vino buono per compensare
    Grazie
  • Re: [Command Pattern] un chiarimento

    Cyrano ha scritto:


    Sto leggendo anche sulle lambda
    L'espressione della lambda diventa a runtime il riferimento ad un oggetto (creato dal runtime) che implementa la functional interface.
Devi accedere o registrarti per scrivere nel forum
10 risposte