Autumn SALE
Polecenie

Polecenie w języku C++

Polecenie to behawioralny wzorzec projektowy według którego żądania lub proste działania są konwertowane na obiekty.

Wyżej wymieniona konwersja pozwala odkładać zadania w czasie, uruchamiać je zdalnie, przechowywać ich historię, itp.

Złożoność:

Popularność:

Przykłady użycia: Wzorzec Polecenie jest dość powszechny w kodzie napisanym w C++ jako alternatywa dla wywołania zwrotnego (ang. callback) zakładającego przypisanie akcji elementom interfejsu użytkownika. Jest stosowany także w celu kolejkowania zadań, śledzenia historii wykonanych działań, itp.

Identyfikacja: Jeśli widzisz zestaw powiązanych klas odpowiadających konkretnym czynnościom (jak “Kopiuj”, “Wytnij”, “Wyślij”, “Drukuj”, itd.) — może to oznaczać użycie wzorca Polecenie. Takie klasy powinny implementować ten sam interfejs/klasę abstrakcyjną. Polecenia mogą samodzielnie implementować poszczególne czynności lub delegować zadania osobnym obiektom — zwanym odbiorcami. Ostatnim elementem układanki jest znalezienie obiektu wywołującego — będzie to klasa przyjmująca obiekty-polecenia w charakterze parametrów swoich metod lub konstruktora.

Przykład koncepcyjny

Poniższy przykład ilustruje strukturę wzorca Polecenie ze szczególnym naciskiem na następujące kwestie:

  • Z jakich składa się klas?
  • Jakie role pełnią te klasy?
  • W jaki sposób elementy wzorca są ze sobą powiązane?

main.cc: Przykład koncepcyjny

/**
 * The Command interface declares a method for executing a command.
 */
class Command {
 public:
  virtual ~Command() {
  }
  virtual void Execute() const = 0;
};
/**
 * Some commands can implement simple operations on their own.
 */
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";
  }
};

/**
 * The Receiver classes contain some important business logic. They know how to
 * perform all kinds of operations, associated with carrying out a request. In
 * fact, any class may serve as a Receiver.
 */
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";
  }
};

/**
 * However, some commands can delegate more complex operations to other objects,
 * called "receivers."
 */
class ComplexCommand : public Command {
  /**
   * @var Receiver
   */
 private:
  Receiver *receiver_;
  /**
   * Context data, required for launching the receiver's methods.
   */
  std::string a_;
  std::string b_;
  /**
   * Complex commands can accept one or several receiver objects along with any
   * context data via the constructor.
   */
 public:
  ComplexCommand(Receiver *receiver, std::string a, std::string b) : receiver_(receiver), a_(a), b_(b) {
  }
  /**
   * Commands can delegate to any methods of a receiver.
   */
  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_);
  }
};

/**
 * The Invoker is associated with one or several commands. It sends a request to
 * the command.
 */
class Invoker {
  /**
   * @var Command
   */
 private:
  Command *on_start_;
  /**
   * @var Command
   */
  Command *on_finish_;
  /**
   * Initialize commands.
   */
 public:
  ~Invoker() {
    delete on_start_;
    delete on_finish_;
  }

  void SetOnStart(Command *command) {
    this->on_start_ = command;
  }
  void SetOnFinish(Command *command) {
    this->on_finish_ = command;
  }
  /**
   * The Invoker does not depend on concrete command or receiver classes. The
   * Invoker passes a request to a receiver indirectly, by executing a 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();
    }
  }
};
/**
 * The client code can parameterize an invoker with any commands.
 */

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: Wynik działania

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

Polecenie w innych językach

Polecenie w języku C# Polecenie w języku Go Polecenie w języku Java Polecenie w języku PHP Polecenie w języku Python Polecenie w języku Ruby Polecenie w języku Rust Polecenie w języku Swift Polecenie w języku TypeScript