Фасад (Facade)

Facade предоставляет небольшой согласованный интерфейс к нескольким частям подсистемы. Он не прячет существование всех компонентов, а даёт клиенту подходящую точку входа для типового сценария.

Проблема

Без фасада controller может сам координировать:

repository
→ permission checker
→ external client
→ mapper
→ event publisher

Тогда порядок шагов и обработка ошибки дублируются в нескольких местах.

Пример

public final class ReportFacade {
    private final ReportRepository repository;
    private final AccessPolicy accessPolicy;
    private final ExportClient exportClient;
 
    public ReportFacade(
            ReportRepository repository,
            AccessPolicy accessPolicy,
            ExportClient exportClient
    ) {
        this.repository = repository;
        this.accessPolicy = accessPolicy;
        this.exportClient = exportClient;
    }
 
    public ExportResult export(long reportId, User user) {
        Report report = repository.findById(reportId)
                .orElseThrow(ReportNotFound::new);
        accessPolicy.checkExport(user, report);
        return exportClient.export(ReportPayload.from(report));
    }
}

Клиент знает один use case export, а facade координирует внутренние collaborators.

Что остаётся снаружи

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

Хороший facade:

  • говорит языком use case;
  • не возвращает внутренние mutable objects;
  • определяет error contract;
  • не содержит случайный набор несвязанных методов;
  • тестируется через наблюдаемый результат.

Цена

  • появляется ещё один слой вызова;
  • чрезмерный facade становится God Object;
  • подсистема может протекать наружу через исключения и типы;
  • транзакционная граница должна быть определена явно;
  • удалённые вызовы внутри фасада не становятся атомарными вместе с БД.

Отличия

  • Адаптер Adapter меняет несовместимый interface;
  • Декоратор Decorator сохраняет interface и добавляет обязанность;
  • Заместитель Proxy сохраняет interface и контролирует доступ;
  • Facade создаёт более удобный высокоуровневый interface для подсистемы.

Вопросы для собеседования

  1. Обязан ли facade скрыть все классы подсистемы? Нет.
  2. Может ли facade быть application service? Да, если выражает use case и координирует зависимости.
  3. Главный риск? Собрать в одном классе все несвязанные операции системы.
  4. Чем отличается от Adapter? Facade упрощает доступ, Adapter согласует два контракта.

Связанные заметки