Поиск по сайту

 

Паттерны » Паттерны поведения » Template Method

Паттерн Template Method (шаблонный метод)

Назначение паттерна Template Method

  • Паттерн Template Method определяет основу алгоритма и позволяет подклассам изменить некоторые шаги этого алгоритма без изменения его общей структуры.
  • Базовый класс определяет шаги алгоритма с помощью абстрактных операций, а производные классы их реализуют.

Решаемая проблема

Имеются два разных, но в тоже время очень похожих компонента. Вы хотите внести изменения в оба компонента, избежав дублирования кода.

Обсуждение паттерна Template Method

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

Проектировщик компонента определяет необходимые шаги алгоритма, порядок их выполнения, но позволяет клиентам компонента расширять или замещать некоторые из этих шагов.

Паттерн Template Method широко применяется в каркасах приложений (frameworks). Каждый каркас реализует неизменные части архитектуры в предметной области, а также определяет те части, которые могут или должны настраиваться клиентом. Таким образом, каркас приложения становится "центром вселенной", а настройки клиента являются просто "третьей планетой от Солнца". Эту инвертированную структуру кода ласково называют принципом Голливуда - "Не звоните нам, мы сами вам позвоним".

Структура паттерна Template Method

UML-диаграмма классов паттерна Template Method

UML-диаграмма классов паттерна Template Method

Реализация метода templateMethod() вызывает методы stepOne(), stepTwo() и stepThree(). Метод stepTwo() является "замещающим" методом. Он объявлен в базовом классе, а определяется в производных классах. Каркасы приложений широко используют паттерн Тemplate Method. Весь повторно используемый код определяется в базовых классах каркаса, нужное поведение системы клиенты определяют в создаваемых производных классах.

UML-диаграмма классов паттерна Template Method. Алгоритм сортировки

Пример паттерна Template Method

Паттерн Template Method определяет основу алгоритма и позволяет подклассам изменить некоторые шаги этого алгоритма без изменения его общей структуры. Строители зданий используют шаблонный метод при проектировании новых домов. Здесь могут использоваться уже существующие типовые планы, в которых модифицируются только отдельные части.

Пример паттерна Template Method

Использование паттерна Template Method

  1. Исследуйте алгоритм и решите, какие шаги являются стандартными, а какие должны определяться подклассами.
  2. Создайте новый абстрактный базовый класс, в котором будет реализован принцип "не звоните нам, мы сами вам позвоним".
  3. Поместите в новый класс основу алгоритма (шаблонный метод) и определения стандартных шагов.
  4. Для каждого шага, требующего различные реализации, определите "замещающий" виртуальный метод. Этот метод может иметь реализацию по умолчанию или быть чисто виртуальным.
  5. Вызовите "замещающий" метод из шаблонного метода.
  6. Создайте подклассы от нового абстрактного базового класса и реализуйте в них "замещающие" методы.

Особенности паттерна Template Method

  • Template Method использует наследование для модификации части алгоритма. Стратегия использует делегирование для модификации всего алгоритма.
  • Стратегия изменяет логику отдельных объектов. Template Method изменяет логику всего класса.
  • Фабричные методы часто вызываются из шаблонных методов.

Реализация паттерна Template Method

  1. Стандартизуйте основу алгоритма в шаблонном методе базового класса.
  2. Для шагов, требующих особенной реализации, определите "замещающие" методы.
  3. Производные классы реализуют "замещающие" методы.
#include <iostream>
using namespace std;

class Base
{
    void a()
    {
        cout << "a  ";
    }
    void c()
    {
        cout << "c  ";
    }
    void e()
    {
        cout << "e  ";
    }
    // 2. Для шагов, требующих особенной реализации, определите 
    //    "замещающие" методы.
    virtual void ph1() = 0;
    virtual void ph2() = 0;
  public:
    // 1. Стандартизуйте основу алгоритма в шаблонном методе 
    //    базового класса
    void execute()
    {
        a();
        ph1();
        c();
        ph2();
        e();
    }
};

class One: public Base
{
   // 3. Производные классы реализуют "замещающие" методы.
     /*virtual*/void ph1()
    {
        cout << "b  ";
    }
     /*virtual*/void ph2()
    {
        cout << "d  ";
    }
};

class Two: public Base
{
     /*virtual*/void ph1()
    {
        cout << "2  ";
    }
     /*virtual*/void ph2()
    {
        cout << "4  ";
    }
};

int main()
{
  Base *array[] = 
  {
     &One(), &Two()
  };
  for (int i = 0; i < 2; i++)
  {
    array[i]->execute();
    cout << '\n';
  }
}

Вывод программы:

a b c d e a 2 c 4 e

Источник: http://sourcemaking.com/design_patterns/template_method/