Глянь мой новый курс по Git! Привет! Глянь мой новый курс по Git! Привет! Глянь мой новый курс по Git на GitByBit.com! Привет! Хочешь круто подтянуть Git? Глянь мой новый курс на GitByBit.com!
Декоратор

Декоратор на C++

Декоратор — это структурный паттерн, который позволяет добавлять объектам новые поведения на лету, помещая их в объекты-обёртки.

Декоратор позволяет оборачивать объекты бесчисленное количество раз благодаря тому, что и обёртки, и реальные оборачиваемые объекты имеют общий интерфейс.

Сложность:

Популярность:

Применимость: Паттерн можно часто встретить в C++ коде, особенно в коде, работающем с потоками данных.

Признаки применения паттерна: Декоратор можно распознать по создающим методам, которые принимают в параметрах объекты того же абстрактного типа или интерфейса, что и текущий класс.

Концептуальный пример

Этот пример показывает структуру паттерна Декоратор, а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.

main.cc: Пример структуры паттерна

/**
 * Базовый интерфейс Компонента определяет поведение, которое изменяется
 * декораторами.
 */
class Component {
 public:
  virtual ~Component() {}
  virtual std::string Operation() const = 0;
};
/**
 * Конкретные Компоненты предоставляют реализации поведения по умолчанию. Может
 * быть несколько вариаций этих классов.
 */
class ConcreteComponent : public Component {
 public:
  std::string Operation() const override {
    return "ConcreteComponent";
  }
};
/**
 * Базовый класс Декоратора следует тому же интерфейсу, что и другие компоненты.
 * Основная цель этого класса - определить интерфейс обёртки для всех конкретных
 * декораторов. Реализация кода обёртки по умолчанию может включать в себя поле
 * для хранения завёрнутого компонента и средства его инициализации.
 */
class Decorator : public Component {
  /**
   * @var Component
   */
 protected:
  Component* component_;

 public:
  Decorator(Component* component) : component_(component) {
  }
  /**
   * Декоратор делегирует всю работу обёрнутому компоненту.
   */
  std::string Operation() const override {
    return this->component_->Operation();
  }
};
/**
 * Конкретные Декораторы вызывают обёрнутый объект и изменяют его результат
 * некоторым образом.
 */
class ConcreteDecoratorA : public Decorator {
  /**
   * Декораторы могут вызывать родительскую реализацию операции, вместо того,
   * чтобы вызвать обёрнутый объект напрямую. Такой подход упрощает расширение
   * классов декораторов.
   */
 public:
  ConcreteDecoratorA(Component* component) : Decorator(component) {
  }
  std::string Operation() const override {
    return "ConcreteDecoratorA(" + Decorator::Operation() + ")";
  }
};
/**
 * Декораторы могут выполнять своё поведение до или после вызова обёрнутого
 * объекта.
 */
class ConcreteDecoratorB : public Decorator {
 public:
  ConcreteDecoratorB(Component* component) : Decorator(component) {
  }

  std::string Operation() const override {
    return "ConcreteDecoratorB(" + Decorator::Operation() + ")";
  }
};
/**
 * Клиентский код работает со всеми объектами, используя интерфейс Компонента.
 * Таким образом, он остаётся независимым от конкретных классов компонентов, с
 * которыми работает.
 */
void ClientCode(Component* component) {
  // ...
  std::cout << "RESULT: " << component->Operation();
  // ...
}

int main() {
  /**
   * Таким образом, клиентский код может поддерживать как простые компоненты...
   */
  Component* simple = new ConcreteComponent;
  std::cout << "Client: I've got a simple component:\n";
  ClientCode(simple);
  std::cout << "\n\n";
  /**
   * ...так и декорированные.
   *
   * Обратите внимание, что декораторы могут обёртывать не только простые
   * компоненты, но и другие декораторы.
   */
  Component* decorator1 = new ConcreteDecoratorA(simple);
  Component* decorator2 = new ConcreteDecoratorB(decorator1);
  std::cout << "Client: Now I've got a decorated component:\n";
  ClientCode(decorator2);
  std::cout << "\n";

  delete simple;
  delete decorator1;
  delete decorator2;

  return 0;
}

Output.txt: Результат выполнения

Client: I've got a simple component:
RESULT: ConcreteComponent

Client: Now I've got a decorated component:
RESULT: ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent))

Декоратор на других языках программирования

Декоратор на C# Декоратор на Go Декоратор на Java Декоратор на PHP Декоратор на Python Декоратор на Ruby Декоратор на Rust Декоратор на Swift Декоратор на TypeScript