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

Что такое шаблон проектирования Chain of Responsibility?

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

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

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

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

Паттерн Chain of Responsibility (Цепочка ответственности)

Chain of Responsibility — это поведенческий паттерн проектирования, который предоставляет способ передать запрос последовательно через цепь объектов. Каждый объект в цепи решает либо обработать запрос, либо передать его следующему объекту в цепи.

Проблема

Представьте, что нужно обработать заявку через несколько уровней проверки (валидация, проверка прав, проверка баланса). Обычный подход приводит к множеству вложенных условных операторов:

public class RequestProcessor {
    public void process(Request request) {
        // Уровень 1: Валидация
        if (!isValid(request)) {
            throw new InvalidRequestException();
        }
        
        // Уровень 2: Проверка прав
        if (!hasPermission(request)) {
            throw new UnauthorizedException();
        }
        
        // Уровень 3: Проверка баланса
        if (!hasSufficientBalance(request)) {
            throw new InsufficientBalanceException();
        }
        
        // Уровень 4: Обработка
        processRequest(request);
    }
}

Проблемы:

  • Трудно добавлять новые обработчики
  • Тесно связанный код
  • Нарушается принцип Single Responsibility
  • Сложно перестраивать цепь

Решение: Chain of Responsibility

Базовый интерфейс обработчика:

public abstract class RequestHandler {
    protected RequestHandler nextHandler;
    
    public void setNextHandler(RequestHandler nextHandler) {
        this.nextHandler = nextHandler;
    }
    
    // Шаблонный метод
    public void handle(Request request) {
        if (canHandle(request)) {
            process(request);
            // Обработка закончена, не передаём дальше
        } else if (nextHandler != null) {
            // Передаём следующему обработчику
            nextHandler.handle(request);
        } else {
            // Никто не обработал
            throw new UnhandledException("No handler for request: " + request);
        }
    }
    
    protected abstract boolean canHandle(Request request);
    protected abstract void process(Request request);
}

Конкретные обработчики:

// Обработчик валидации
public class ValidationHandler extends RequestHandler {
    @Override
    protected boolean canHandle(Request request) {
        // Этот обработчик всегда срабатывает первым
        return true;
    }
    
    @Override
    protected void process(Request request) {
        System.out.println("Validating request...");
        if (request.getAmount() <= 0) {
            throw new InvalidRequestException("Amount must be positive");
        }
        if (request.getUserId() == null) {
            throw new InvalidRequestException("User ID is required");
        }
        System.out.println("Validation passed");
        
        // Передаём дальше
        if (nextHandler != null) {
            nextHandler.handle(request);
        }
    }
}

// Обработчик проверки прав
public class AuthorizationHandler extends RequestHandler {
    private AuthService authService;
    
    public AuthorizationHandler(AuthService authService) {
        this.authService = authService;
    }
    
    @Override
    protected boolean canHandle(Request request) {
        return true;
    }
    
    @Override
    protected void process(Request request) {
        System.out.println("Checking permissions...");
        if (!authService.hasPermission(request.getUserId(), "TRANSFER_MONEY")) {
            throw new UnauthorizedException(
                "User " + request.getUserId() + " has no permission"
            );
        }
        System.out.println("Authorization passed");
        
        if (nextHandler != null) {
            nextHandler.handle(request);
        }
    }
}

// Обработчик проверки баланса
public class BalanceHandler extends RequestHandler {
    private AccountService accountService;
    
    public BalanceHandler(AccountService accountService) {
        this.accountService = accountService;
    }
    
    @Override
    protected boolean canHandle(Request request) {
        return true;
    }
    
    @Override
    protected void process(Request request) {
        System.out.println("Checking balance...");
        BigDecimal balance = accountService.getBalance(request.getUserId());
        if (balance.compareTo(request.getAmount()) < 0) {
            throw new InsufficientBalanceException(
                "Balance " + balance + " < Amount " + request.getAmount()
            );
        }
        System.out.println("Balance check passed");
        
        if (nextHandler != null) {
            nextHandler.handle(request);
        }
    }
}

// Финальный обработчик - обработка запроса
public class ProcessingHandler extends RequestHandler {
    private TransactionService transactionService;
    
    public ProcessingHandler(TransactionService transactionService) {
        this.transactionService = transactionService;
    }
    
    @Override
    protected boolean canHandle(Request request) {
        return true;
    }
    
    @Override
    protected void process(Request request) {
        System.out.println("Processing transaction...");
        Transaction transaction = transactionService.executeTransfer(
            request.getUserId(),
            request.getRecipient(),
            request.getAmount()
        );
        System.out.println("Transaction completed: " + transaction.getId());
        // Это последний обработчик, не передаём дальше
    }
}

Конфигурация цепи:

@Configuration
public class ChainConfiguration {
    
    @Bean
    public RequestHandler requestChain(
            AuthService authService,
            AccountService accountService,
            TransactionService transactionService) {
        
        // Строим цепь в нужном порядке
        RequestHandler validation = new ValidationHandler();
        RequestHandler authorization = new AuthorizationHandler(authService);
        RequestHandler balance = new BalanceHandler(accountService);
        RequestHandler processing = new ProcessingHandler(transactionService);
        
        // Связываем обработчики
        validation.setNextHandler(authorization);
        authorization.setNextHandler(balance);
        balance.setNextHandler(processing);
        
        return validation;  // Возвращаем первый обработчик
    }
}

Использование:

@Service
public class MoneyTransferService {
    private final RequestHandler chain;
    
    public MoneyTransferService(RequestHandler chain) {
        this.chain = chain;
    }
    
    public void transfer(String userId, String recipient, BigDecimal amount) {
        Request request = new Request(userId, recipient, amount);
        chain.handle(request);  // Запускаем цепь
    }
}

// Использование в контроллере
@RestController
public class TransferController {
    private final MoneyTransferService transferService;
    
    @PostMapping("/api/transfer")
    public ResponseEntity<String> transfer(@RequestBody TransferRequest req) {
        try {
            transferService.transfer(
                req.getUserId(),
                req.getRecipient(),
                req.getAmount()
            );
            return ResponseEntity.ok("Transfer successful");
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
}

Вывод цепи:

Validating request...
Validation passed
Checking permissions...
Authorization passed
Checking balance...
Balance check passed
Processing transaction...
Transaction completed: TXN-12345

Альтернатива: с использованием фильтров (более гибко)

functional interface RequestFilter {
    void filter(Request request, FilterChain chain);
}

public class FilterChain {
    private List<RequestFilter> filters = new ArrayList<>();
    private int currentIndex = 0;
    
    public void addFilter(RequestFilter filter) {
        filters.add(filter);
    }
    
    public void process(Request request) {
        if (currentIndex < filters.size()) {
            RequestFilter filter = filters.get(currentIndex++);
            filter.filter(request, this);
        }
    }
}

// Использование
FilterChain chain = new FilterChain();
chain.addFilter((request, next) -> {
    System.out.println("Filter 1");
    next.process(request);
});
chain.addFilter((request, next) -> {
    System.out.println("Filter 2");
    next.process(request);
});
chain.process(request);

Реальные примеры Chain of Responsibility

1. Servlet Filters в Spring:

public class LoggingFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain) throws ServletException, IOException {
        System.out.println("Request: " + request.getRequestURI());
        filterChain.doFilter(request, response);  // Передаём дальше
        System.out.println("Response status: " + response.getStatus());
    }
}

2. Exception handling в Java:

try {
    // код
} catch (SpecificException e) {
    // обработка 1
} catch (GeneralException e) {
    // обработка 2
}

3. Event listeners:

public interface EventListener {
    void onEvent(Event event);
}

public class EventDispatcher {
    private List<EventListener> listeners = new ArrayList<>();
    
    public void dispatch(Event event) {
        for (EventListener listener : listeners) {
            listener.onEvent(event);
        }
    }
}

Преимущества паттерна

  • Слабая связанность — обработчики независимы друг от друга
  • Single Responsibility — каждый обработчик отвечает за одно
  • Open/Closed — легко добавлять новые обработчики
  • Гибкость — порядок обработчиков можно изменять динамически
  • Разделение ответственности — логика распределена по разным классам

Когда использовать

  • Множество объектов, которые могут обработать запрос
  • Заранее неизвестен, кто именно обработает запрос
  • Нужна возможность динамически менять цепь обработки
  • Нужна обработка в несколько этапов с проверками

Chain of Responsibility — мощный паттерн для создания гибких и расширяемых систем обработки запросов, особенно популярен в фреймворках и middleware архитектурах.