Паттерн «Шаблонный метод»

В шаблоне «Шаблонный метод» абстрактный класс публично определяет способ/шаблон выполнения своих методов. Его подклассы могут при необходимости переопределять реализации методов, но вызов будет выполняться способом, определенным в абстрактном классе. Этот тип шаблона проектирования является поведенческим шаблоном.

Введение

назначение

Скелет алгоритма определяется в родительском классе, а подклассам разрешено переопределять некоторые конкретные шаги алгоритма, не изменяя структуру алгоритма.

Основные решаемые проблемы

  • Это решает проблему повторной реализации одних и тех же методов в нескольких подклассах путем вынесения общих методов в родительский класс, чтобы избежать дублирования кода.

Сценарий использования

  • Когда есть общие методы, которые могут совместно использоваться несколькими подклассами.

Подход к реализации

  • Определите абстрактный родительский класс: содержит шаблонный метод и некоторые абстрактные или конкретные методы.
  • Конкретный подкласс: наследует абстрактный родительский класс и реализует абстрактные методы, не изменяя структуру алгоритма.

Ключевой код

  • Шаблонный метод: Определяется в абстрактном родительском классе, вызывает абстрактные методы и конкретные методы.
  • Абстрактный метод: Реализуется подклассами и представляет вариативные части алгоритма.
  • Конкретный метод: Реализуется в абстрактном родительском классе и представляет инвариантные части алгоритма.

Пример приложения

  • Процесс строительства: Такие этапы, как фундамент, электропроводка и сантехника, одинаковы, а последующие этапы строительства, такие как добавление кладовок и заборов, различаются.
  • 81 испытание из «Путешествия на Запад»: 81 испытание, установленное Бодхисаттвой, представляет собой логический каркас верхнего уровня.
  • Поддержка Hibernate в Spring: Инкапсулирует общие методы, такие как открытие транзакции, получение Session и закрытие Session.

Преимущества

  • Инкапсулируйте инвариантные части: Инвариантная часть алгоритма инкапсулируется в родительском классе.
  • Расширяйте вариативные части: Подклассы могут расширять или изменять вариативные части алгоритма.
  • Выделяйте общий код: Снижает дублирование кода и облегчает сопровождение.

Недостатки

  • Увеличение числа классов: Каждая отличающаяся реализация требует подкласса, что может привести к разбуханию системы.

Рекомендации по использованию

  • Когда несколько подклассов имеют общие методы с идентичной логикой, рассмотрите возможность использования паттерна «Шаблонный метод».
  • Для важных или сложных методов можно рассмотреть возможность определения их как шаблонных методов в родительском классе.

Примечания

  • Чтобы предотвратить вредоносное изменение, шаблонный метод обычно объявляется final.finalМодификация с помощью ключевого слова, чтобы избежать переопределения подклассами.

Основные задействованные роли

  • Абстрактный родительский класс (Abstract Class):

    • Определяет шаблонный метод и некоторые абстрактные или конкретные методы.
  • Конкретные классы:

    • Наследуются от абстрактного родительского класса и реализуют абстрактные методы.
  • Хук-метод (необязательно):

    • Определён в абстрактном родительском классе, может быть переопределён подклассами, чтобы влиять на поведение шаблонного метода.
  • Клиент (необязательно):

    • Использование абстрактных родительских классов и конкретных подклассов без необходимости вникать в детали шаблонного метода.

Реализация

Мы создадим класс, определяющий операцииGameабстрактный класс, в котором шаблонный метод объявлен final, поэтому он не будет переопределён.CricketиFootballРасширяетGameКонкретные классы, которые переопределяют методы абстрактного класса.

TemplatePatternDemo, а наш демонстрационный класс использует егоGame, чтобы продемонстрировать использование паттерна «Шаблонный метод».

模板模式的 UML 图

Шаг 1

Создайте абстрактный класс, в котором шаблонный метод объявлен как final.

Game.java

public abstract class Game { abstract void initialize(); abstract void startPlay(); abstract void endPlay(); //Шаблоны public final void play(){ //Инициализировать игру initialize(); //Начать игру startPlay(); //Завершить игру endPlay(); } }

Шаг 2

Создайте классы сущностей, расширяющие вышеуказанный класс.

Cricket.java

public class Cricket extends Game { @Override void endPlay() { System.out.println("Игра в крикет завершена!"); } @Override void initialize() { System.out.println("Игра в крикет инициализирована! Начните играть."); } @Override void startPlay() { System.out.println("Игра в крикет началась. Приятной игры!"); } }

Football.java

public class Football extends Game { @Override void endPlay() { System.out.println("Игра в футбол завершена!"); } @Override void initialize() { System.out.println("Игра в футбол инициализирована! Начните играть."); } @Override void startPlay() { System.out.println("Игра в футбол началась. Приятной игры!"); } }

Шаг 3

ИспользованиеGameИспользуйте шаблонный метод play(), чтобы продемонстрировать, как определена игра.

TemplatePatternDemo.java

public class TemplatePatternDemo { public static void main(String[] args) { Game game = new Cricket(); game.play(); System.out.println(); game = new Football(); game.play(); } }

Шаг 4

Запустите программу и выведите результаты:

Cricket Game Initialized! Start playing.
Cricket Game Started. Enjoy the game!
Cricket Game Finished!

Football Game Initialized! Start playing.
Football Game Started. Enjoy the game!
Football Game Finished!
Другие расширения