Паттерн «Шаблонный метод»
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 73 из 87.
Шаблонный метод (Template Method Pattern) — это поведенческий паттерн проектирования, который определяет скелет алгоритма в базовом классе, позволяя подклассам переопределять конкретные шаги, не изменяя общую структуру. Представьте это как рецепт: общий процесс приготовления остается неизменным, но отдельные ингредиенты или техники могут варьироваться.
Этот паттерн использует абстрактный класс с шаблонным методом, который вызывает последовательность шагов. Некоторые шаги имеют реализации по умолчанию, в то время как другие являются абстрактными и должны быть реализованы подклассами:
abstract class DataProcessor {
// Шаблонный метод — определяет структуру алгоритма
public final void process() {
readData();
processData();
saveData();
}
abstract void readData();
abstract void processData();
// Реализация по умолчанию (метод-хук)
void saveData() {
System.out.println("Saving to default location");
}
}
class CSVProcessor extends DataProcessor {
void readData() {
System.out.println("Reading CSV file");
}
void processData() {
System.out.println("Parsing CSV data");
}
}
class XMLProcessor extends DataProcessor {
void readData() {
System.out.println("Reading XML file");
}
void processData() {
System.out.println("Parsing XML data");
}
}Шаблонный метод обычно помечается как final, чтобы предотвратить изменение структуры алгоритма подклассами. При вызове он выполняет одну и ту же последовательность действий для всех подклассов:
DataProcessor csv = new CSVProcessor();
csv.process();
// Вывод:
// Чтение CSV файла
// Парсинг CSV данных
// Сохранение в расположение по умолчаниюПаттерн «Шаблонный метод» (Template Method Pattern) идеально подходит в тех случаях, когда у вас есть алгоритмы, имеющие одинаковую структуру, но различающиеся в конкретных шагах. Он способствует повторному использованию кода, размещая общую логику в базовом классе и позволяя настраивать её через наследование.
Задание
ЛегкоДавайте создадим систему генерации документов, используя паттерн «Шаблонный метод» (Template Method Pattern)! Вы создадите структуру, в которой различные типы документов (отчеты и счета) следуют одному и тому же процессу генерации, но настраивают конкретные шаги под себя. Это идеально подходит для сценариев, где общий рабочий процесс фиксирован, но детали различаются в зависимости от типа документа.
Вы организуете свой код в четырех файлах:
DocumentGenerator.java: Создайте абстрактный базовый класс, который определяет шаблонный метод. ВашDocumentGeneratorдолжен содержать:Метод
finalс именемgenerateDocument(), который определяет скелет алгоритма, вызывая по порядку три шага:createHeader(),createBody()иcreateFooter().Два абстрактных метода:
createHeader()иcreateBody(), которые должны реализовать подклассы.Метод-перехватчик (hook)
createFooter()с реализацией по умолчанию, которая выводит--- End of Document ---.ReportGenerator.java: Создайте конкретный подкласс для генерации отчетов. Он должен принимать заголовок отчета (String) через конструктор.Метод
createHeader()выводит=== REPORT: [title] ===Метод
createBody()выводитReport content goes here...Используйте унаследованный нижний колонтитул по умолчанию.
InvoiceGenerator.java: Создайте еще один конкретный подкласс для генерации счетов. Он должен принимать имя клиента (String) и сумму (double) через конструктор.Метод
createHeader()выводит*** INVOICE ***Метод
createBody()выводитCustomer: [name]на одной строке, затемAmount Due: $[amount]на следующей строке (отформатируйте сумму до двух знаков после запятой).Переопределите
createFooter(), чтобы вывестиThank you for your business!Main.java: Объедините вашу систему шаблонных методов! Вы получите три входных значения: заголовок отчета (String), имя клиента (String) и сумму счета (double).Создайте
ReportGeneratorс заголовком и вызовитеgenerateDocument(). Выведите пустую строку для разделения. Затем создайтеInvoiceGeneratorс именем клиента и суммой и вызовитеgenerateDocument().
Вы получите три входных значения по порядку: заголовок отчета (String), имя клиента (String) и сумма счета (double).
Например, при входных данных Q4 Sales, Acme Corp и 1500.00 ваш вывод будет следующим:
=== REPORT: Q4 Sales ===
Report content goes here...
--- End of Document ---
*** INVOICE ***
Customer: Acme Corp
Amount Due: $1500.00
Thank you for your business!Обратите внимание, как оба типа документов следуют одному и тому же трехэтапному процессу, определенному в шаблонном методе, но каждый настраивает шаги по-своему. ReportGenerator использует нижний колонтитул по умолчанию, в то время как InvoiceGenerator предоставляет свой собственный — в этом и заключается сила методов-перехватчиков в паттерне «Шаблонный метод»!
Шпаргалка
Шаблонный метод (Template Method Pattern) — это поведенческий паттерн проектирования, который определяет основу алгоритма в базовом классе, позволяя подклассам переопределять определенные шаги, не изменяя общую структуру.
Паттерн использует абстрактный класс с шаблонным методом, который вызывает последовательность шагов. Некоторые шаги имеют реализации по умолчанию, в то время как другие являются абстрактными и должны быть реализованы подклассами:
abstract class DataProcessor {
// Шаблонный метод — определяет структуру алгоритма
public final void process() {
readData();
processData();
saveData();
}
abstract void readData();
abstract void processData();
// Реализация по умолчанию (метод-хук)
void saveData() {
System.out.println("Saving to default location");
}
}Конкретные подклассы реализуют абстрактные методы:
class CSVProcessor extends DataProcessor {
void readData() {
System.out.println("Reading CSV file");
}
void processData() {
System.out.println("Parsing CSV data");
}
}Шаблонный метод помечен как final, чтобы предотвратить изменение структуры алгоритма подклассами. При вызове он выполняет одну и ту же последовательность для всех подклассов:
DataProcessor csv = new CSVProcessor();
csv.process();
// Output:
// Reading CSV file
// Parsing CSV data
// Saving to default locationОсновные характеристики:
- Шаблонный метод является
finalи определяет структуру алгоритма - Абстрактные методы должны быть реализованы подклассами
- Методы-хуки (hooks) предоставляют реализации по умолчанию, которые могут быть опционально переопределены
- Способствует повторному использованию кода путем размещения общей логики в базовом классе
Попробуйте сами
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Чтение входных данных
String reportTitle = scanner.nextLine();
String customerName = scanner.nextLine();
double invoiceAmount = scanner.nextDouble();
// TODO: Создайте ReportGenerator с заголовком и вызовите generateDocument()
// TODO: Выведите пустую строку для разделения
// TODO: Создайте InvoiceGenerator с именем клиента и суммой, и вызовите generateDocument()
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»