Паттерн Шаблонный метод на C++
Шаблонный метод – это поведенческий паттерн, задающий скелет алгоритма в суперклассе и заставляющий подклассы реализовать конкретные шаги этого алгоритма.
Особенности паттерна на 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