Шаблон Template Method

Шаблон Template Method применяется, когда есть алгоритм, состоящий из нескольких шагов. Но в разных классах он реализуется по-разному.

Пример

Например, мы строим ледовое сооружение (ледовую горку или фигуру). Шаги такие:

  1. Собрать снег
  2. Сформировать снег
  3. Залить водой
  4. Сделать что-то еще (не обязательный шаг)

При этом ледовая фигура Снегурочки и  ледовая горка отличаются шагом 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.

 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *