Il modello di comando è per incapsulare i comandi negli oggetti. Ma perché non usare invece i puntatori di funzione. Perché devo sottoclasse la classe Command per ogni operazione? Invece posso avere diverse funzioni e chiamare quelle funzioni per memorizzare i puntatori e così via ...Motivo di comando: perché incapsulato in un oggetto
risposta
Ma perché non utilizzare invece i puntatori di funzione.
Perché i puntatori di funzione non possono memorizzare lo stato arbitrario. Spesso vorrete che il comando sia parametrizzato quando lo create. Per esempio:
struct command {
virtual ~command() {}
virtual void do_it() = 0;
};
struct say_something : command {
// store a message to print later
say_something(std::string message) : message(message) {}
// print the stored message
void do_it() override {std::cout << message << '\n';}
std::string message;
};
std::unique_ptr<command> say_hello(new say_something("Hello!"));
// later
say_hello->do_it(); // prints stored string
Se si sceglie di usare un puntatore a funzione semplice, allora avresti bisogno di una funzione diversa per tutto ciò che si potrebbe desiderare di stampare.
Perché ho bisogno di sottoclasse classe di comando per ogni operazione?
Perché è così che funziona l'OOP vecchia scuola; anche se, come accennato in precedenza, è possibile utilizzare il fatto che si tratta di un oggetto per parametrizzarlo invece di suddividerlo in sottoclasse.
Fortunatamente, moderno C++ ha strutture migliori:
typedef std::function<void()> command;
// print a static string
command say_hello = []{std::cout << "Hello!\n";};
// store a string to print later
std::string goodbye = "Goodbye!";
command say_goodbye = [goodbye]{std::cout << goodbye << '\n';};
// later
say_hello(); // prints static string
say_goodbye(); // prints string stored in the command
modello di comando è molto più di una semplice esecuzione di una funzione. Incapsula dati e logica all'interno di una classe e fornisce un oggetto che può essere facilmente passato come parametro. Oltre ad eseguire attività, potrebbe anche generare eventi, analizzare e pulire i dati e molto altro, ed è qui che i metodi di ereditarietà e di template sono utili, che non si otterranno con i puntatori di funzione. Inoltre, implementare undo e redo è molto semplice usando i comandi.
+1 per ereditarietà, annulla e ripristina (più funzioni correlate al comando) e incapsula i dati (ad esempio lo stato) – Narek
Citazione "Se si dovesse utilizzare un puntatore a funzione semplice, sarà necessaria una funzione diversa per tutto ciò che si desidera stampare." Ma tu non devi. Puoi chiamare la funzione con diversi parametri, mentre crei un comando con argomenti diversi. – Narek
@Narek ma il pattern Command non ti consente di fornire argomenti quando invochi il comando, solo quando lo crei. Quindi hai bisogno di un oggetto per archiviarli in modo che siano disponibili quando è invocato. –