Menu
Coddy logo textTech

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

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

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

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

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");
}

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

DataProcessor csv = new CsvProcessor();
csv.Process();
// Чтение CSV файла
// Парсинг CSV данных
// Saving to default location

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

Паттерн Template Method идеально подходит, когда несколько классов имеют одинаковую структуру algorithm, но различаются на отдельных этапах. Он способствует повторному использованию кода, размещая общую логику в base class и обеспечивая гибкость с помощью методов, которые можно переопределить.

challenge icon

Задание

Легко

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

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

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

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

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

Создайте подходящий генератор отчётов на основе входных данных и вызовите его method 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

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

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

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

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

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

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