Шаблон Template Method применяется, когда есть алгоритм, состоящий из нескольких шагов. Но в разных классах он реализуется по-разному.
Пример
Например, мы строим ледовое сооружение (ледовую горку или фигуру). Шаги такие:
- Собрать снег
- Сформировать снег
- Залить водой
- Сделать что-то еще (не обязательный шаг)
При этом ледовая фигура Снегурочки и ледовая горка отличаются шагом 2 — снег формируется для них в разную форму. А шаги 1 и 3 остаются одинаковыми.
Реализация шаблона Template Method
Мы создаем абстрактный класс, от которого будут наследоваться Снегурочка и горка. И в нем создаем Template Method (назовем его build() — построить). Он вызывает последовательно шаги алгоритма. Те шаги, которые отличаются, мы переопределяем в классах-наследниках.
Что касается шага «Сделать что-то еще» — это хук. Он создается на всякий случай и имеет пустое тело. Он тоже вызывается из Template Method. Хук добавляется, если есть необязательный шаг, то есть шаг, который нужен не всем подклассам. Например, снегурочку надо поставить на постамент, а горку — не надо. Поэтому только снегурочка переопределяет этот метод. А для горки он вызывается с пустым телом.
Итак, создадим абстрактный Класс IceStructure (ледовое сооружение), от которого будут наследоваться снегурочка и горка. Здесь build() — это Template Method:
public abstract class IceStructure { //template method public void build() { collectSnow(); // шаг 1, собрать снег formSnow(); // шаг 2, сформировать снег fillWithWater(); // шаг 3, залить водой //hook additionalAction(); // шаг 4, сделать что-то еще } protected void collectSnow() { System.out.println("собрать снег"); } abstract protected void formSnow(); protected void fillWithWater() { System.out.println("залить водой"); } //hook с пустым телом protected void additionalAction() { } }
Из build() последовательно вызываются все шаги алгоритма, включая пустотелый additionalAction(). В нем снегурочка будет ставиться на постамент.
Классы-наследники
Класс IceSlide (горка); в нем переопределен метод, специфичный для горки:
public class IceSlide extends IceStructure { @Override protected void formSnow() { System.out.println("сформировать горку"); } }
Класс Snegurochka; в нем переопределены методы, специфичные для снегурочки (включая хук):
public class Snegurochka extends IceStructure { @Override protected void formSnow() { System.out.println("сформировать снегурочку"); } // переопределяем хук @Override protected void additionalAction() { System.out.println("поставить на постамент"); } }
Вызов Template Method
Вызывается Template Method так:
public class Main { public static void main(String[] args) { IceStructure iceSlide = new IceSlide(); iceSlide.build(); IceStructure snegurochka = new Snegurochka(); snegurochka.build(); } }
Внутри Template Method последовательно вызываются все шаги алгоритма: как общие, так и отличающиеся от наследника к наследнику. В итоге для горки получим такой результат:
собрать снег сформировать горку залить водой
А для снегурочки такой:
собрать снег сформировать снегурочку залить водой поставить на постамент
Итоги
Благодаря шаблону получился не дублирующийся код.
Вызываем мы метод абстрактного класса, а не подклассов, что тоже хорошо.
Исходный код примера есть на GitHub.