← Назад к вопросам

Что такое шаблонный метод?

2.2 Middle🔥 101 комментариев
#SOLID и паттерны проектирования

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Шаблонный метод (Template Method Pattern)

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

Основная идея

Шаблонный метод — это метод базового класса, который:

  1. Определяет скелет алгоритма
  2. Вызывает абстрактные методы, которые переопределяют подклассы
  3. Остаётся неизменяемым (помечается как final)

Структура паттерна

public abstract class DataProcessor {
    
    // Шаблонный метод
    public final void process() {
        readData();
        validateData();
        transformData();
        saveData();
    }
    
    // Абстрактные методы
    protected abstract void readData();
    protected abstract void transformData();
    protected abstract void saveData();
    
    // Конкретная реализация
    protected void validateData() {
        System.out.println("Валидация");
    }
}

public class CsvProcessor extends DataProcessor {
    
    @Override
    protected void readData() {
        System.out.println("Чтение CSV");
    }
    
    @Override
    protected void transformData() {
        System.out.println("Трансформация");
    }
    
    @Override
    protected void saveData() {
        System.out.println("Сохранение");
    }
}

Примеры в Java

1. HttpServlet

public abstract class HttpServlet extends GenericServlet {
    
    protected void service(HttpServletRequest request, HttpServletResponse response) {
        if ("GET".equals(request.getMethod())) {
            doGet(request, response);
        } else if ("POST".equals(request.getMethod())) {
            doPost(request, response);
        }
    }
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        throw new HttpRequestMethodNotSupportedException("Not supported");
    }
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) {
        throw new HttpRequestMethodNotSupportedException("Not supported");
    }
}

public class UserServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        // Реализация GET
    }
    
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) {
        // Реализация POST
    }
}

2. Spring Framework

Spring часто использует Template Method в JdbcTemplate, RestTemplate и т.д.

public abstract class AbstractApplicationContext {
    
    public final void refresh() {
        prepareRefresh();
        obtainFreshBeanFactory();
        prepareBeanFactory();
        postProcessBeanFactory();  // Для переопределения
        beanFactory.preInstantiateSingletons();
    }
    
    protected abstract ConfigurableListableBeanFactory obtainFreshBeanFactory();
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {}
}

Реальный пример: обработка документов

public abstract class DocumentProcessor {
    
    public final void processDocument(String filePath) {
        try {
            System.out.println("Начало: " + filePath);
            Document doc = openDocument(filePath);
            validateDocument(doc);
            Document result = transformDocument(doc);
            saveDocument(result);
            System.out.println("Успешно");
        } catch (Exception e) {
            handleError(e);
        } finally {
            cleanup();
        }
    }
    
    protected abstract Document openDocument(String filePath) throws IOException;
    protected abstract Document transformDocument(Document doc) throws Exception;
    protected abstract void saveDocument(Document doc) throws IOException;
    
    protected void validateDocument(Document doc) {
        if (doc == null) throw new IllegalArgumentException("Document is null");
    }
    
    protected void handleError(Exception e) {
        System.err.println("Error: " + e.getMessage());
    }
    
    protected void cleanup() {
        System.out.println("Cleanup");
    }
}

public class PdfProcessor extends DocumentProcessor {
    
    @Override
    protected Document openDocument(String filePath) throws IOException {
        return new PdfDocument(PDDocument.load(new File(filePath)));
    }
    
    @Override
    protected Document transformDocument(Document doc) {
        // Трансформация PDF
        return doc;
    }
    
    @Override
    protected void saveDocument(Document doc) throws IOException {
        doc.save("output.pdf");
    }
}

public class WordProcessor extends DocumentProcessor {
    
    @Override
    protected Document openDocument(String filePath) throws IOException {
        return new WordDocument(new XWPFDocument(new FileInputStream(filePath)));
    }
    
    @Override
    protected Document transformDocument(Document doc) {
        // Трансформация Word
        return doc;
    }
    
    @Override
    protected void saveDocument(Document doc) throws IOException {
        doc.save("output.docx");
    }
}

// Использование
DocumentProcessor pdfProcessor = new PdfProcessor();
pdfProcessor.processDocument("document.pdf");

DocumentProcessor wordProcessor = new WordProcessor();
wordProcessor.processDocument("document.docx");

Плюсы Template Method

1. Переиспользование кода

Общая логика в базовом классе, специфичная реализация в подклассах:

// Общее для всех процессоров
// Специфичное — только в подклассах

2. Консистентность

Все подклассы следуют одной структуре алгоритма.

3. Инверсия управления

Базовый класс управляет потоком выполнения, не подклассы.

4. Легко расширять

Добавление нового типа процессора требует только создания подкласса:

public class ExcelProcessor extends DocumentProcessor {
    // Реализация для Excel
}

5. Single Responsibility

Каждый подкласс отвечает только за свои шаги.

Минусы Template Method

1. Наследование

Привязаны к иерархии классов.

2. Нарушение открытости расширения

Для изменения порядка шагов нужно менять базовый класс.

3. Глубокая иерархия

Много уровней наследования усложняет понимание.

4. Хрупкий базовый класс

Изменение базового класса может сломать все подклассы.

Template Method vs Strategy

Template Method (наследование):

public abstract class PaymentProcessor {
    public final void process() {
        validate();
        charge();
        notify();
    }
    
    protected abstract void charge();
    protected abstract void notify();
}

Strategy (композиция):

public class PaymentProcessor {
    private ChargeStrategy chargeStrategy;
    private NotificationStrategy notificationStrategy;
    
    public void process() {
        validate();
        chargeStrategy.charge();
        notificationStrategy.notify();
    }
}

Strategy лучше для:

  • Динамической смены поведения в runtime
  • Избежания глубокой иерархии классов
  • Композиции вместо наследования

Выводы

Template Method Pattern:

  • Идеален для фиксированного алгоритма с вариативными шагами
  • Повсеместно используется в Java (Servlets, Collections, Spring)
  • Альтернатива: Strategy Pattern для большей гибкости
  • Помни о инверсии управления: не подклассы вызывают базовый класс, а базовый вызывает подклассы