기능 하나를 쓰려고 서브시스템의 여러 클래스를 순서대로 호출해야 하는 경우가 있다. 홈시어터에서 영화를 보려면 앰프를 켜고, 프로젝터를 켜고, 조명을 낮추고, 플레이어를 재생해야 한다. 클라이언트가 이 순서와 각 컴포넌트를 전부 알아야 하면 서브시스템에 강하게 결합된다. Facade 는 그 앞에 단순한 인터페이스 하나를 두어 이 복잡성을 감춘다.
공통 의도
Facade 의 의도는 세 가지다.
- 단일 진입점 — 서브시스템의 여러 호출을 하나의 인터페이스로 묶는다. 클라이언트는
watchMovie()하나만 호출한다. - 결합도 완화 — 클라이언트가 서브시스템 내부 클래스를 직접 알 필요가 없다. 내부 구조가 바뀌어도 Facade 뒤에서 흡수된다.
- 선택적 사용 — Facade 는 서브시스템을 감추되 막지는 않는다. 세밀한 제어가 필요한 클라이언트는 내부 클래스에 직접 접근할 수도 있다.
GoF 원형
GoF 에서 Facade 는 서브시스템 클래스들을 조율하는 단일 객체다. 클라이언트는 Facade 만 알고, Facade 가 내부 컴포넌트들의 호출 순서와 의존을 담당한다.
flowchart LR
Client --> Facade
Facade --> Amp["Amplifier"]
Facade --> Proj["Projector"]
Facade --> Lights
Facade --> Player
class HomeTheaterFacade {
private final Amplifier amp;
private final Projector projector;
private final Lights lights;
private final Player player;
void watchMovie(String title) {
lights.dim(10);
projector.on();
amp.on();
player.play(title);
}
}
클라이언트는 watchMovie() 만 부른다. 켜는 순서나 각 컴포넌트의 존재는 Facade 안에 숨는다. 서브시스템 클래스들은 그대로 남아 있고, Facade 는 그 위에 얇은 조율 계층을 더할 뿐이다.
언어별 구현
Java 에서는 서비스 레이어가 사실상 Facade 역할을 한다. OrderService.placeOrder() 하나가 재고 확인, 결제, 배송 요청을 순서대로 조율한다. 컨트롤러는 이 세 서브시스템을 직접 알 필요가 없다.
class OrderService {
void placeOrder(Order order) {
inventory.reserve(order);
payment.charge(order);
shipping.schedule(order);
}
}
Python 은 모듈 자체가 Facade 가 되곤 한다. requests 라이브러리가 대표적이다. 내부적으로 urllib3 의 커넥션 풀, 인코딩, 리다이렉트 처리를 감추고 requests.get(url) 이라는 단순한 진입점만 노출한다.
TypeScript 에서는 SDK 클라이언트가 Facade 다. HTTP 요청, 인증 토큰 갱신, 직렬화를 내부에 감추고 client.users.list() 같은 메서드만 드러낸다. 사용자는 그 뒤의 복잡성을 몰라도 된다.
Adapter, Mediator 와의 구분
셋 다 다른 객체 앞에 서지만 목적이 다르다.
- Facade — 복잡한 서브시스템에 단순한 진입점을 준다. 방향은 클라이언트에서 서브시스템으로 단방향이다.
- Adapter — 인터페이스를 변환한다. 기존 클래스를 클라이언트가 기대하는 다른 인터페이스에 맞추는 게 목적이다.
- Mediator — 객체들 사이의 상호작용을 중앙으로 모은다. 여러 객체가 서로 직접 참조하지 않고 Mediator 를 거쳐 양방향으로 조정된다.
Facade 는 단순화, Adapter 는 변환, Mediator 는 조정이다.
결론
Facade 는 복잡한 서브시스템에 단순한 진입점을 제공해 결합도를 낮춘다. 서브시스템을 감추되 막지 않으므로, 대부분의 클라이언트는 Facade 만 쓰고 세밀한 제어가 필요한 경우만 내부로 들어간다. 판단은 한 가지 질문으로 좁혀진다.
- 클라이언트가 여러 컴포넌트의 호출 순서와 의존을 알아야 하는가. 그렇다면 그 조율을 Facade 로 옮긴다.
서비스 레이어, 라이브러리 SDK, 모듈 인터페이스가 모두 Facade 의 실무 형태다. 인터페이스를 바꾸는 Adapter, 양방향으로 조정하는 Mediator 와는 목적으로 갈린다.