Menu
Coddy logo textTech

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

Часть раздела Объектно-ориентированное программирование путешествия по C# на Coddy — урок 59 из 70.

Паттерн Шаблонный метод — это поведенческий паттерн, который определяет скелет алгоритма в базовом классе, позволяя подклассам переопределять конкретные шаги, не меняя общую структуру. Базовый класс управляет рабочим процессом, в то время как производные классы настраивают отдельные части.

Этот паттерн использует наследование и абстрактные методы. Базовый класс содержит «шаблонный метод», который вызывает последовательность шагов, некоторые из которых являются абстрактными и должны быть реализованы подклассами:

public abstract class DataProcessor
{
    // Шаблонный метод — определяет структуру алгоритма
    public void Process()
    {
        ReadData();
        ProcessData();
        SaveData();
    }
    
    protected abstract void ReadData();
    protected abstract void ProcessData();
    protected virtual void SaveData() => Console.WriteLine("Saving to default location");
}

public class CsvProcessor : DataProcessor
{
    protected override void ReadData() => Console.WriteLine("Reading CSV file");
    protected override void ProcessData() => Console.WriteLine("Parsing CSV data");
}

public class JsonProcessor : DataProcessor
{
    protected override void ReadData() => Console.WriteLine("Reading JSON file");
    protected override void ProcessData() => Console.WriteLine("Parsing JSON data");
    protected override void SaveData() => Console.WriteLine("Saving to cloud");
}

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

DataProcessor csv = new CsvProcessor();
csv.Process();
// Чтение CSV файла
// Парсинг CSV данных
// Сохранение в расположение по умолчанию

DataProcessor json = new JsonProcessor();
json.Process();
// Чтение JSON файла
// Парсинг JSON данных
// Сохранение в облако

Шаблонный метод (Template Method) идеально подходит в тех случаях, когда несколько классов имеют одинаковую структуру алгоритма, но различаются в конкретных шагах. Он способствует повторному использованию кода, размещая общую логику в базовом классе и обеспечивая гибкость за счет переопределяемых методов.

challenge icon

Задание

Легко

Давайте создадим систему генерации отчетов, используя паттерн «Шаблонный метод» (Template Method). Различные типы отчетов (например, отчеты о продажах и отчеты об инвентаризации) имеют общую структуру — всем им нужно собрать данные, отформатировать их и вывести результат — но каждый тип отчета обрабатывает эти шаги по-своему.

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

  • ReportGenerator.cs: Создайте абстрактный класс ReportGenerator в пространстве имен Reporting. Этот базовый класс определяет скелет алгоритма генерации отчета через шаблонный метод с именем Generate(). Метод должен последовательно вызывать три шага: GatherData(), FormatReport() и OutputReport(). Сделайте GatherData() и FormatReport() абстрактными (каждый тип отчета будет реализовывать их по-разному), в то время как OutputReport() должен быть виртуальным методом с реализацией по умолчанию, которая выводит Sending to default printer.
  • ConcreteReports.cs: Создайте два конкретных класса отчетов в том же пространстве имен, которые наследуются от ReportGenerator:
    • SalesReport — реализует GatherData() для вывода Collecting sales data from database и FormatReport() для вывода Formatting as sales summary
    • InventoryReport — реализует GatherData() для вывода Scanning warehouse inventory, FormatReport() для вывода Formatting as inventory list, и переопределяет OutputReport() для вывода Sending to warehouse manager
  • Program.cs: Объедините все вместе, создавая экземпляры отчетов и генерируя их. Шаблонный метод гарантирует, что каждый отчет следует одному и тому же трехэтапному процессу, но конкретное поведение каждого шага варьируется в зависимости от типа отчета.

Вы получите один входной параметр:

  • Тип отчета: sales или inventory

Создайте соответствующий генератор отчетов на основе входных данных и вызовите его метод Generate().

Например, если на входе sales, вывод должен быть следующим:

Collecting sales data from database
Formatting as sales summary
Sending to default printer

Если на входе inventory, вывод должен быть следующим:

Scanning warehouse inventory
Formatting as inventory list
Sending to warehouse manager

Обратите внимание, что оба отчета следуют одной и той же структуре алгоритма (сбор, форматирование, вывод), но реализация каждого шага настроена индивидуально. SalesReport использует поведение вывода по умолчанию, в то время как InventoryReport переопределяет его — это демонстрирует, как паттерн «Шаблонный метод» позволяет вам контролировать, какие шаги обязательны для переопределения, а какие могут быть настроены по желанию!

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

using System;
using Reporting;

class Program
{
    public static void Main(string[] args)
    {
        string reportType = Console.ReadLine();
        
        // TODO: Создайте соответствующий генератор отчетов на основе reportType
        // Если reportType равен "sales", создайте SalesReport
        // Если reportType равен "inventory", создайте InventoryReport
        // Затем вызовите метод Generate() для отчета
        
    }
}
quiz iconПроверьте себя

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

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