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 переопределяет его — это демонстрирует, как паттерн Шаблонный метод позволяет вам контролировать, какие шаги обязательны для переопределения, а какие могут быть настроены по желанию!

Шпаргалка

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

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

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();
// Reading CSV file
// Parsing CSV data
// Saving to default location

DataProcessor json = new JsonProcessor();
json.Process();
// Reading JSON file
// Parsing JSON data
// Saving to cloud

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

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

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Проверьте себя

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

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