복잡한 서브시스템 앞에 단순한 창구 하나를 두는 패턴.
// Before — 클라이언트가 내부 절차를 전부 알아야 한다
videoFile = new VideoFile(name);
sourceCodec = codecFactory.extract(videoFile);
buffer = BitrateReader.read(filename, sourceCodec);
result = BitrateReader.convert(buffer, destinationCodec);
result = AudioMixer.fix(result);
// After — 창구 하나
class VideoConverter {
File convert(String name, String format) { ...위 절차 전부... }
}
new VideoConverter().convert("a.ogg", "mp4");
감추되 막지는 않는다
-
Facade 는 서브시스템 접근을 '금지' 하지 않는다
- 세밀한 제어가 필요한 클라이언트는 여전히 내부를 직접 쓸 수 있다
-
이 점이 Proxy 와 다르다. Proxy 는 접근을 통제한다
비슷해 보이는 것들과의 구분
| Facade | 여러 개를 하나의 '쉬운' 창구로 | 인터페이스가 달라진다(단순화) |
|---|---|---|
| Adapter | 하나를 다른 '모양' 으로 맞춘다 | 인터페이스가 달라진다(변환) |
| Proxy | 같은 인터페이스로 접근을 '통제' | 인터페이스가 같다 |
| Decorator | 같은 인터페이스로 기능을 '추가' | 인터페이스가 같다 |
대가 — 만능 객체가 되기 쉽다
편하다는 이유로 계속 메서드를 붙이면 Facade 가 모든 것을 아는 God Object 로 자란다
- 서브시스템별로 Facade 를 나누거나, 진짜 필요한 시나리오만 노출한다
실무에서
Spring JdbcTemplate // Connection·Statement·ResultSet 절차를 감춘다
SLF4J LoggerFactory
애플리케이션 서비스 계층 // 여러 도메인 서비스를 한 유스케이스로 묶는다
면접 함정
- ❌ "내부 접근을 차단한다" → 막지 않는다. 쉬운 길을 하나 더 줄 뿐이다.
- ❌ Adapter와 혼동 → Facade는 단순화, Adapter는 호환이 목적이다.
계층 경계에서 자주 쓴다
@Service
class OrderFacade {
@Transactional
OrderResult place(OrderCommand cmd) {
inventoryService.reserve(cmd);
paymentService.charge(cmd);
orderService.create(cmd);
return ...;
}
}
컨트롤러가 서비스 5개를 직접 부르면 트랜잭션 경계와 유스케이스 흐름이 컨트롤러로 새어 나온다. Facade를 두면 한 곳에 모인다.
Mediator와의 차이
-
Facade — 단방향 — 클라이언트 → 서브시스템. 서브시스템은 Facade 를 모른다
-
Mediator — 양방향 — 참여자들이 중재자를 통해 서로 소통한다
-
Facade 는 '입구', Mediator 는 '교환대'
얇게 유지한다
Facade에 비즈니스 규칙이 쌓이기 시작하면 도메인 로직이 서비스 계층으로 새어 나온 것이다(빈약한 도메인 모델). Facade의 역할은 순서를 조율하고 트랜잭션을 긋는 것까지고, 판단·규칙은 도메인 객체가 갖는다.