Menu
Coddy logo textTech

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

Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy. Урок 97 из 110.

Паттерн Template Method defines скелет algorithm в base class, позволяя подклассам переопределять отдельные шаги без изменения общей структуры. Base class управляет рабочим процессом, а подклассы настраивают отдельные шаги.

Этот паттерн использует наследование: abstract class defines шаблонный метод, который вызывает последовательность шагов; некоторые из них являются абстрактными (их должны implement подклассы), а для некоторых есть реализации по умолчанию:

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();
  // Чтение CSV файла
  // Разбор строк CSV
  // Данные сохранены в базу данных

  var json = JsonProcessor();
  json.process();
  // Чтение JSON файла
  // Разбор объектов JSON
  // Сохранено в облачное хранилище
}

Метод process() — это шаблон: он defines порядок операций. Подклассы реализуют readData() и processData() differently и могут при необходимости переопределить saveData(). Главное преимущество заключается в том, что структура algorithm остаётся согласованной во всех реализациях, обеспечивая гибкость отдельных шагов.

challenge icon

Задание

Легко

Давайте создадим систему генерации отчётов с использованием шаблона Template Method! Вы создадите framework, в котором разные типы отчётов следуют одной общей структуре, но каждый тип отчёта настраивает определённые шаги, такие как сбор data и форматирование результата.

Вы организуете код в два файла:

  • report_generator.dart: Этот файл содержит ваш abstract базовый класс и Concrete реализации отчётов. Создайте abstract класс ReportGenerator с шаблонным методом generate(), который определяет workflow генерации отчёта в следующем порядке: fetchData(), analyzeData(), formatReport() и deliver(). Методы fetchData() и formatReport() должны быть abstract (каждый тип отчёта обрабатывает их differently), а analyzeData() должен выводить Analyzing data..., и deliver() должен выводить Report delivered via email. в качестве Default реализаций. Затем создайте два Concrete класса отчётов:
    • 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: Импортируйте файл генератора отчётов и продемонстрируйте, как шаблон Template Method сохраняет согласованной структуру algorithm, позволяя выполнять настройку. Создайте экземпляр SalesReport и вызовите его метод generate(). Затем выведите пустую строку для разделения. Создайте экземпляр InventoryReport и также вызовите его метод generate().

Обратите внимание, что оба отчёта следуют одному и тому же процессу из четырёх шагов, но каждый настраивает шаги, важные для его конкретного назначения. InventoryReport даже переопределяет Default метод доставки, чтобы отправлять отчёты другому получателю!

Ожидаемый результат:

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.

Попробуйте сами

import 'report_generator.dart';

void main() {
  // TODO: Создайте SalesReport и вызовите его метод generate()

  // TODO: Выведите пустую строку для разделения

  // TODO: Создайте InventoryReport и вызовите его метод generate()
}
quiz iconПроверьте себя

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

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

Потренируйтесь самостоятельно: Онлайн-компилятор Dart