Назначение: определяет основу алгоритма и позволяет подклассам переопределить некоторые шаги алгоритма, не изменяя его структуру в целом.
Задача. Рассмотрим каркас приложения, в котором имеются классы Application и Document. Класс Application отвечает за открытие существующих документов, хранящихся во внешнем формате, например в виде файла. Объект класса Document представляет информацию документа после его прочтения из файла. Приложения, построенные на базе этого каркаса, могут порождать подклассы от классов Application и Document, отвечающие конкретным потребностям. Например, графический редактор определит подклассы DrawApplication и DrawDocument, а электронная таблица – подклассы SpreadsheetApplication и SpreadsheetDocument.
Очевидно, что логика алгоритма открытия документов в любом приложении достаточно однотипна:
1) проверяется, можно ли в текущем состоянии приложения открыть документ;
2) производится выбор имени файла (например, предлагается пользователю сделать это в диалоговом окне);
3) проверяется сам факт существования указанного файла, корректность его формата;
4) выполняется специализированное для каждого приложения считывание внутренней информации файла и создается объект-документ;
5) документ добавляется к списку документов приложения.
Таким образом, возникает задача исключения избыточности алгоритмов операций создания документов в классах иерархии Application.
Решение. Паттерн Шаблонный Метод предлагает определить в абстрактном классе Application общий алгоритм открытия и считывания документа в виде операции OpenDocument. Программный код такой операции может выглядеть так:
if (CanOpenDocument())
{
string filename = SelectFileName();
if (FileExists(filename))
{
Document doc = LoadDocument(filename);
documents.Add(doc);
}
}
Операции, подобные OpenDocument, называют шаблонными методами. Они описывают алгоритм в терминах абстрактных операций, которые замещены в подклассах для получения нужного поведения. Подклассы класса Application самостоятельно определяют, как выполнить проверку возможности открытия (CanOpenDocument), как выбрать файл (SelectFileName), корректность выбранного файла (FileExists), а также сам процесс конструирования документа на основе информации из файла (LoadDocument).
Определяя некоторые шаги алгоритма с помощью абстрактных операций, шаблонный метод фиксирует их последовательность, но позволяет реализовать их в подклассах. При этом сохраняется общий ход алгоритма и конкретика некоторых шагов, которые неизменны для потомков.
Общая структура решения.
AbstractClass (Application) – абстрактный класс: определяет абстрактные примитивные операции, замещаемые в конкретных подклассах для реализации шагов алгоритма; реализует шаблонный метод TemplateMethod, определяющий скелет алгоритма. Шаблонный метод вызывает примитивные операции PrimitiveOperation, а также операции, определенные в классе AbstractClass или в других объектах.
ConcreteClass (DrawApplication) – конкретный класс: реализует примитивные операции, выполняющие шаги алгоритма способом, специфическим для данного подкласса.
ConcreteClass предполагает, что инвариантные шаги алгоритма будут выполнены в AbstractClass.
Применимость. Используйте паттерн Шаблонный Метод:
Результаты. Шаблонные методы – один из фундаментальных приемов повторного использования кода. Они особенно важны в библиотеках классов, поскольку предоставляют возможность вынести общее поведение в библиотечные классы.
Шаблонные методы приводят к инвертированной структуре кода, которую иногда называют принципом Голливуда, подразумевая часто употребляемую в этой киноимперии фразу «Не звоните нам, мы сами позвоним». В данном случае это означает, что родительский класс вызывает операции подкласса, а не как обычно – наоборот.
Особенности реализации:
Родственные паттерны.
Фабричные Методы часто вызываются из Шаблонных Методов (в примере шаблонный метод OpenDocument вызывал фабричный метод LoadDocument).
Стратегия: Шаблонные Методы применяют наследование для модификации части алгоритма. Стратегии используют делегирование для модификации алгоритма в целом.