Паттерн Команда на C++
Команда – это поведенческий паттерн, позволяющий заворачивать запросы или простые операции в отдельные объекты.
Это позволяет откладывать выполнение команд, выстраивать их в очереди, а также хранить историю и делать отмену.
Особенности паттерна на C++
Сложность:
Популярность:
Применимость: Паттерн можно часто встретить в C++ коде, особенно когда нужно откладывать выполнение команд, выстраивать их в очереди, а также хранить историю и делать отмену.
Признаки применения паттерна: Классы команд построены вокруг одного действия и имеют очень узкий контекст. Объекты команд часто подаются в обработчиках событий элементов GUI. Практически любая реализация отмены использует принцип команд.
Концептуальный пример
Этот пример показывает структуру паттерна Команда, а именно – из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
main.cc: Пример структуры паттерна
/**
* Интерфейс Команды объявляет метод для выполнения команд.
*/
class Command {
public:
virtual ~Command() {
}
virtual void Execute() const = 0;
};
/**
* Некоторые команды способны выполнять простые операции самостоятельно.
*/
class SimpleCommand : public Command {
private:
std::string pay_load_;
public:
explicit SimpleCommand(std::string pay_load) : pay_load_(pay_load) {
}
void Execute() const override {
std::cout << "SimpleCommand: See, I can do simple things like printing (" << this->pay_load_ << ")\n";
}
};
/**
* Классы Получателей содержат некую важную бизнес-логику. Они умеют выполнять
* все виды операций, связанных с выполнением запроса. Фактически, любой класс
* может выступать Получателем.
*/
class Receiver {
public:
void DoSomething(const std::string &a) {
std::cout << "Receiver: Working on (" << a << ".)\n";
}
void DoSomethingElse(const std::string &b) {
std::cout << "Receiver: Also working on (" << b << ".)\n";
}
};
/**
* Но есть и команды, которые делегируют более сложные операции другим объектам,
* называемым «получателями».
*/
class ComplexCommand : public Command {
/**
* @var Receiver
*/
private:
Receiver *receiver_;
/**
* Данные о контексте, необходимые для запуска методов получателя.
*/
std::string a_;
std::string b_;
/**
* Сложные команды могут принимать один или несколько объектов-получателей
* вместе с любыми данными о контексте через конструктор.
*/
public:
ComplexCommand(Receiver *receiver, std::string a, std::string b) : receiver_(receiver), a_(a), b_(b) {
}
/**
* Команды могут делегировать выполнение любым методам получателя.
*/
void Execute() const override {
std::cout << "ComplexCommand: Complex stuff should be done by a receiver object.\n";
this->receiver_->DoSomething(this->a_);
this->receiver_->DoSomethingElse(this->b_);
}
};
/**
* Отправитель связан с одной или несколькими командами. Он отправляет запрос
* команде.
*/
class Invoker {
/**
* @var Command
*/
private:
Command *on_start_;
/**
* @var Command
*/
Command *on_finish_;
/**
* Инициализация команд.
*/
public:
~Invoker() {
delete on_start_;
delete on_finish_;
}
void SetOnStart(Command *command) {
this->on_start_ = command;
}
void SetOnFinish(Command *command) {
this->on_finish_ = command;
}
/**
* Отправитель не зависит от классов конкретных команд и получателей.
* Отправитель передаёт запрос получателю косвенно, выполняя команду.
*/
void DoSomethingImportant() {
std::cout << "Invoker: Does anybody want something done before I begin?\n";
if (this->on_start_) {
this->on_start_->Execute();
}
std::cout << "Invoker: ...doing something really important...\n";
std::cout << "Invoker: Does anybody want something done after I finish?\n";
if (this->on_finish_) {
this->on_finish_->Execute();
}
}
};
/**
* Клиентский код может параметризовать отправителя любыми командами.
*/
int main() {
Invoker *invoker = new Invoker;
invoker->SetOnStart(new SimpleCommand("Say Hi!"));
Receiver *receiver = new Receiver;
invoker->SetOnFinish(new ComplexCommand(receiver, "Send email", "Save report"));
invoker->DoSomethingImportant();
delete invoker;
delete receiver;
return 0;
}
Output.txt: Результат выполнения
Invoker: Does anybody want something done before I begin?
SimpleCommand: See, I can do simple things like printing (Say Hi!)
Invoker: ...doing something really important...
Invoker: Does anybody want something done after I finish?
ComplexCommand: Complex stuff should be done by a receiver object.
Receiver: Working on (Send email.)
Receiver: Also working on (Save report.)