Шаблонный метод на C++
Шаблонный метод — это поведенческий паттерн, задающий скелет алгоритма в суперклассе и заставляющий подклассы реализовать конкретные шаги этого алгоритма.
Сложность:
Популярность:
Применимость: Шаблонные методы можно встретить во многих библиотечных классах C++. Разработчики создают их, чтобы позволить клиентам легко и быстро расширять стандартный код при помощи наследования.
Признаки применения паттерна: Класс заставляет своих потомков реализовать методы-шаги, но самостоятельно реализует структуру алгоритма.
Концептуальный пример
Этот пример показывает структуру паттерна Шаблонный метод, а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
main.cc: Пример структуры паттерна
/** * Абстрактный Класс определяет шаблонный метод, содержащий скелет некоторого * алгоритма, состоящего из вызовов (обычно) абстрактных примитивных операций. * * Конкретные подклассы должны реализовать эти операции, но оставить сам * шаблонный метод без изменений. */ class AbstractClass { /** * Шаблонный метод определяет скелет алгоритма. */ public: void TemplateMethod() const { this->BaseOperation1(); this->RequiredOperations1(); this->BaseOperation2(); this->Hook1(); this->RequiredOperation2(); this->BaseOperation3(); this->Hook2(); } /** * Эти операции уже имеют реализации. */ protected: void BaseOperation1() const { std::cout << "AbstractClass says: I am doing the bulk of the work\n"; } void BaseOperation2() const { std::cout << "AbstractClass says: But I let subclasses override some operations\n"; } void BaseOperation3() const { std::cout << "AbstractClass says: But I am doing the bulk of the work anyway\n"; } /** * А эти операции должны быть реализованы в подклассах. */ virtual void RequiredOperations1() const = 0; virtual void RequiredOperation2() const = 0; /** * Это «хуки». Подклассы могут переопределять их, но это не обязательно, * поскольку у хуков уже есть стандартная (но пустая) реализация. Хуки * предоставляют дополнительные точки расширения в некоторых критических * местах алгоритма. */ virtual void Hook1() const {} virtual void Hook2() const {} }; /** * Конкретные классы должны реализовать все абстрактные операции базового * класса. Они также могут переопределить некоторые операции с реализацией по * умолчанию. */ class ConcreteClass1 : public AbstractClass { protected: void RequiredOperations1() const override { std::cout << "ConcreteClass1 says: Implemented Operation1\n"; } void RequiredOperation2() const override { std::cout << "ConcreteClass1 says: Implemented Operation2\n"; } }; /** * Обычно конкретные классы переопределяют только часть операций базового * класса. */ class ConcreteClass2 : public AbstractClass { protected: void RequiredOperations1() const override { std::cout << "ConcreteClass2 says: Implemented Operation1\n"; } void RequiredOperation2() const override { std::cout << "ConcreteClass2 says: Implemented Operation2\n"; } void Hook1() const override { std::cout << "ConcreteClass2 says: Overridden Hook1\n"; } }; /** * Клиентский код вызывает шаблонный метод для выполнения алгоритма. Клиентский * код не должен знать конкретный класс объекта, с которым работает, при * условии, что он работает с объектами через интерфейс их базового класса. */ void ClientCode(AbstractClass *class_) { // ... class_->TemplateMethod(); // ... } int main() { std::cout << "Same client code can work with different subclasses:\n"; ConcreteClass1 *concreteClass1 = new ConcreteClass1; ClientCode(concreteClass1); std::cout << "\n"; std::cout << "Same client code can work with different subclasses:\n"; ConcreteClass2 *concreteClass2 = new ConcreteClass2; ClientCode(concreteClass2); delete concreteClass1; delete concreteClass2; return 0; } Output.txt: Результат выполнения
Same client code can work with different subclasses: AbstractClass says: I am doing the bulk of the work ConcreteClass1 says: Implemented Operation1 AbstractClass says: But I let subclasses override some operations ConcreteClass1 says: Implemented Operation2 AbstractClass says: But I am doing the bulk of the work anyway Same client code can work with different subclasses: AbstractClass says: I am doing the bulk of the work ConcreteClass2 says: Implemented Operation1 AbstractClass says: But I let subclasses override some operations ConcreteClass2 says: Overridden Hook1 ConcreteClass2 says: Implemented Operation2 AbstractClass says: But I am doing the bulk of the work anyway