Patterns. Паттерн Template Method

Паттерн Template Method (реализация схемы)

1. Общие сведения. Назначение. Участники паттерна

Паттерн Template Method (Шаблонный метод) относится к паттернам поведения классов. Шаблонный метод определяет шаги алгоритма и позволяет подклассам определять некоторые из этих шагов. При этом структура самого алгоритма не меняется.

Суть шаблона состоит в том, что в некоторый абстрактный класс помещаются.

  • методы (операции) описывающие алгоритм. Эти методы называются шаблонными. В своем теле они обращаются к методам, реализуемым в унаследованных классах;
  • методы, которые замещаются в унаследованных классах. Эти методы определяют нужное поведение.

Структура (диаграмма классов) паттерна Template Method приведена на рисунке 1.

Паттерн Template Method (шаблонный метод). Диаграмма классов

Рисунок 1. Структура (диаграмма классов) паттерна Template Method

Участниками паттерна являются следующие элементы (см. рисунок 1).

  1. AbstractClass – абстрактный класс, определяющий:
  • перечень примитивных методов (операций), замещаемых в конкретных подклассах;
  • один или несколько шаблонных методов, определяющих шаги (основу) алгоритма. Шаблонный метод вызывает примитивные методы, реализуемые в AbstractClass или в других объектах.
  1. ConcreteClass – конкретный класс. Реализует примитивные методы (операции), выполняющие шаги алгоритма. Реализация каждого шага определяется особенностями подкласса.

 

2. Случаи применения

Паттерн Template Method может применяться в следующих случаях:

  • когда нужно реализовать постоянные шаги алгоритма, каждый из которых (шагов) изменяется в зависимости от реализации в подклассах;
  • когда в одном классе нужно выделить общее для всех подклассов поведение во избежание дублирования кода. При таком подходе, сначала, выделяются отличия в коде, а затем эти отличия реализуются в унаследованных классах;
  • когда возникает необходимость в вызове так называемых операций-зацепок (hooks) в определенных точках.

 

3. Пример реализации структуры паттерна на языке C++

В нижеприведенном коде на языке C++ реализован паттерн Template Method.

#include <iostream>
using namespace std;

// Паттерн Template Method – реализация схемы
class AbstractClass abstract
{
public:
  // Шаблонный метод – вызывает методы
  // PrimitiveOperation1(), PrimitiveOperation2()
  void TemplateMethod()
  {
    // реализация алгоритма вызова
    PrimitiveOperation1();
    PrimitiveOperation2();
  }

  virtual void PrimitiveOperation1() = 0;
  virtual void PrimitiveOperation2() = 0;
};

class ConcreteClass : public AbstractClass
{
public:
  // Конкретные реализации операций
  void PrimitiveOperation1()
  {
    cout << "ConcreteClass::PrimitiveOperation1()" << endl;
  }

  void PrimitiveOperation2()
  {
    cout << "ConcreteClass::PrimitiveOperation2()" << endl;
  }
};

int main()
{
  // Создать экземпляр конкретного класса
  AbstractClass* p = new ConcreteClass();

  // Вызвать шаблонный метод
  p->TemplateMethod();

  // Освободить память
  if (p)
    delete p;
}

 

4. Результаты

Для паттерна Template Method можно выделить следующие результаты.

  1. Паттерн разрешает вынести общее поведение в библиотечные классы.
  2. Структура кода в паттерне инвертирована. Это означает, что базовый класс вызывает методы подкласса, а не наоборот.

Методы, вызываемые из базового класса, могут быть следующими видами (см. рисунок 1):

  • конкретные методы (операции). Это методы, вызываемые из классов клиента или класса ConcreteClass. На рисунке 1 такими классами являются: PrimitiveOperation1() и PrimitiveOperation2();
  • конкретные методы из класса AbstractClass. Это методы, которые совместно используются всеми подклассами. На рисунке 1 таковым методом является TemplateMethod();
  • примитивные (абстрактные) методы;
  • фабричные методы. Более подробно о фабричных методах можно посмотреть здесь (паттерн Factory Method);
  • методы-зацепки (операции-зацепки, hooks operations). Это методы, реализующие поведение по умолчанию, допускающее изменение в унаследованных классах. Важно, чтобы у паттерна должны быть четко отделены операции-зацепки от абстрактных операций. Операции-зацепки можно переопределять или не переопределять. Абстрактные операции обязательно следует переопределять.

 

5. Операция-зацепка (hook operation). Пример на C++

 

// Паттерн Template Method
// Пример операции-зацепки (hook operation)
// Базовый класс - реализует метод по умолчанию
class BaseClass
{
public:
  // метод по умолчанию не выполняет никакой работы
  void HookOperation()
  { }

  // Шаблонный метод
  void Operation()
  {
    // Поведение родительского класса ParentClass
    HookOperation();
  }
};

// Унаследованный класс – делает замещение операции
// HookOperation() базового класса
class DerivedClass : public BaseClass
{
public:
  // Здесь расширение поведения
  void HookOperation()
  {
    // выполнение действий, расширяющих метод
    // базового класса
    // ...
  }
};

 

6. Особенности реализации

Для паттерна Template Method можно выделить следующие особенности реализации.

  1. Обеспечение контроля доступа. В этом случае примитивные методы, вызываемые шаблонным методом, можно объявить в разделе protected (защищенными). Это дает возможность вызова этих способов только шаблонным способом. Так же примитивные методы, обязательно должны быть замещенными, объявляются как чисто виртуальные функции.
  2. Сокращение количества простых способов для клиента. Примитивные методы (операции) замещаются в подклассах. Желательно по возможности минимизировать количество примитивных методов для клиента.
  3. Согласование имен. Здесь имеется в виду установка дополнительного префикса к именам методов, которые нужно заместить.