Паттерн Шаблонный метод
Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 97 из 110.
Паттерн Шаблонный метод (Template Method) определяет скелет алгоритма в базовом классе, позволяя подклассам переопределять отдельные шаги, не изменяя общую структуру. Базовый класс управляет рабочим процессом, в то время как подклассы настраивают конкретные шаги.
Этот паттерн использует наследование: абстрактный класс определяет шаблонный метод, который вызывает последовательность шагов, некоторые из которых являются абстрактными (должны быть реализованы подклассами), а некоторые имеют реализации по умолчанию:
abstract class DataProcessor {
// Шаблонный метод — определяет структуру алгоритма
void process() {
readData();
processData();
saveData();
}
void readData(); // Абстрактный метод — подклассы должны реализовать
void processData(); // Абстрактный метод — подклассы должны реализовать
void saveData() { // Реализация по умолчанию
print('Data saved to database');
}
}
class CsvProcessor extends DataProcessor {
@override
void readData() => print('Reading CSV file');
@override
void processData() => print('Parsing CSV rows');
}
class JsonProcessor extends DataProcessor {
@override
void readData() => print('Reading JSON file');
@override
void processData() => print('Parsing JSON objects');
@override
void saveData() => print('Saved to cloud storage');
}
void main() {
var csv = CsvProcessor();
csv.process();
// Reading CSV file
// Parsing CSV rows
// Data saved to database
var json = JsonProcessor();
json.process();
// Reading JSON file
// Parsing JSON objects
// Saved to cloud storage
}Метод process() является шаблоном — он определяет порядок операций. Подклассы реализуют readData() и processData() по-разному и могут по желанию переопределять saveData(). Ключевое преимущество заключается в том, что структура алгоритма остается неизменной во всех реализациях, обеспечивая при этом гибкость на отдельных этапах.
Задание
ЛегкоДавайте создадим систему генерации отчетов, используя паттерн Шаблонный метод (Template Method)! Вы создадите структуру, в которой различные типы отчетов следуют одному и тому же общему алгоритму, но каждый тип отчета настраивает определенные шаги, такие как сбор данных и форматирование вывода.
Вы организуете свой код в двух файлах:
report_generator.dart: Этот файл содержит ваш абстрактный базовый класс и конкретные реализации отчетов. Создайте абстрактный классReportGeneratorс шаблонным методомgenerate(), который определяет рабочий процесс генерации отчета в следующем порядке:fetchData(),analyzeData(),formatReport()иdeliver(). МетодыfetchData()иformatReport()должны быть абстрактными (каждый тип отчета обрабатывает их по-разному), в то время какanalyzeData()должен выводитьAnalyzing data..., аdeliver()должен выводитьReport delivered via email.в качестве реализаций по умолчанию. Затем создайте два конкретных класса отчетов:SalesReport— его методfetchData()выводитFetching sales data from database..., а егоformatReport()выводитFormatting as bar charts and tables.InventoryReport— его методfetchData()выводитFetching inventory levels from warehouse..., егоformatReport()выводитFormatting as inventory list., и он переопределяетdeliver(), чтобы вывестиReport sent to warehouse manager.
main.dart: Импортируйте файл генератора отчетов и продемонстрируйте, как паттерн Шаблонный метод сохраняет структуру алгоритма неизменной, позволяя при этом выполнять настройку. Создайте экземплярSalesReportи вызовите его методgenerate(). Затем выведите пустую строку для разделения. Создайте экземплярInventoryReportи также вызовите его методgenerate().
Обратите внимание, как оба отчета следуют одному и тому же четырехэтапному процессу, но каждый настраивает шаги, важные для его конкретной цели. InventoryReport даже переопределяет метод доставки по умолчанию, чтобы отправлять отчеты другому получателю!
Ожидаемый вывод:
Fetching sales data from database...
Analyzing data...
Formatting as bar charts and tables.
Report delivered via email.
Fetching inventory levels from warehouse...
Analyzing data...
Formatting as inventory list.
Report sent to warehouse manager.Шпаргалка
Паттерн Шаблонный метод (Template Method) определяет основу алгоритма в базовом классе, позволяя подклассам переопределять отдельные шаги, не изменяя общую структуру.
Абстрактный класс определяет шаблонный метод, который вызывает последовательность шагов. Некоторые шаги являются абстрактными (должны быть реализованы подклассами), а некоторые имеют реализации по умолчанию:
abstract class DataProcessor {
// Шаблонный метод — определяет структуру алгоритма
void process() {
readData();
processData();
saveData();
}
void readData(); // Абстрактный — подклассы должны реализовать
void processData(); // Абстрактный — подклассы должны реализовать
void saveData() { // Реализация по умолчанию
print('Data saved to database');
}
}
class CsvProcessor extends DataProcessor {
@override
void readData() => print('Reading CSV file');
@override
void processData() => print('Parsing CSV rows');
}
class JsonProcessor extends DataProcessor {
@override
void readData() => print('Reading JSON file');
@override
void processData() => print('Parsing JSON objects');
@override
void saveData() => print('Saved to cloud storage');
}
Шаблонный метод управляет порядком выполнения рабочего процесса. Подклассы настраивают отдельные шаги, реализуя абстрактные методы и, при необходимости, переопределяя реализации по умолчанию. Структура алгоритма остается неизменной во всех реализациях.
Попробуйте сами
import 'report_generator.dart';
void main() {
// TODO: Создайте SalesReport и вызовите его метод generate()
// TODO: Выведите пустую строку для разделения
// TODO: Создайте InventoryReport и вызовите его метод generate()
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыБиблиотеки и импортВведение в ООПКлассы и объектыКлючевое слово thisМетодыПеременные экземпляраОсновы конструкторовИтоги — Простой калькулятор4Null-безопасность
Введение в Null-безопасностьNullable и Non-Nullable типыОператоры ? и !Ключевое слово Late и Null-безопасностьNull-aware операторыNull-безопасность в классахИтоги — Система профилей пользователей7Абстрактные классы и интерфейсы
Абстрактные классыАбстрактные методыИнтерфейсы в DartНеявные интерфейсыРеализация против наследованияМножественные интерфейсыИтоги — Калькулятор фигур10Коллекции и обобщения
Обзор List, Set, MapТипобезопасные коллекцииОбобщенные классыОбобщенные методыОграничения обобщенийIterable и IteratorИтоги: Обобщенное хранилище13Продвинутые концепции ООП
Композиция против наследованияМетоды расширенияВызываемые классыЗапечатанные классы (Dart 3)Записи (Dart 3)Паттерны и сопоставление (3.0)Перечисления с методами16Проект: Управление библиотекой
Обзор проектаКлассы Book и User2Конструкторы в Dart
Конструктор по умолчаниюИменованные конструкторыСписки инициализацииКонстантные конструкторыФабричные конструкторыПеренаправляющие конструкторыИтоги — Shape Builder5Инкапсуляция
Публичные и приватные членыСоглашение о префиксе _Приватность на уровне библиотекГеттеры и сеттеры: подробный разборСкрытие данныхИтоги — Записи о студентах8Mixins
Введение в MixinsСоздание MixinsИспользование нескольких MixinsКлючевое слово on в MixinsMixin и наследованиеMixin и интерфейсИтоги: Система животных11Специальные методы
Переопределение toString()Переопределение hashCode и ==Интерфейс ComparableМетод call()Переопределение noSuchMethodПовторение — Пользовательская коллекция14Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy3Свойства классов
Члены экземпляра и статические членыПоля Final и ConstПеременные LateСтатические методы и поляГеттеры и сеттерыИтоги — Менеджер банковского счета6Наследование
Основы наследованияКлючевое слово superПереопределение методовАннотация @overrideКлючевое слово final для классовКонструкторы и наследованиеИтоги: Иерархия сотрудников9Полиморфизм
Основы полиморфизмаПолиморфизм через интерфейсыПроверка типов во время выполненияОператоры is и asКлючевое слово covariantИтоги — Обработчик платежей12Асинхронное ООП
Futures и async/awaitОсновы StreamsКонтроллеры StreamАсинхронные конструкторыАсинхронность в методах классовИтоги — Data Fetcher15Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий