Menu
Coddy logo textTech

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

Часть раздела Объектно-ориентированное программирование путешествия по 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(). Ключевое преимущество заключается в том, что структура алгоритма остается неизменной во всех реализациях, обеспечивая при этом гибкость на отдельных этапах.

challenge icon

Задание

Легко

Давайте создадим систему генерации отчетов, используя паттерн Шаблонный метод (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()
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование