프로그래밍/알고리즘&자료구조&패턴

디자인패턴 - 퍼사드 패턴

lazy_web_devloper 2025. 8. 18. 10:52
728x90
반응형

JAVA로 구현하는 알고리즘과 디자인 패턴 공부: 퍼사드 패턴 (Facade)

1. 퍼사드 패턴이란? 🏛️

개념: 복잡한 서브시스템(Subsystem)을 더 쉽게 사용할 수 있도록, 단순하고 통합된 하나의 인터페이스(창구)를 제공하는 패턴입니다. 'Facade'는 프랑스어로 건물의 '정면'을 의미하며, 건물의 복잡한 내부 구조를 감추고 깔끔한 정면만 보여주는 것처럼 동작합니다.

가장 좋은 예는 **홈시어터의 '통합 리모컨'**입니다. 영화를 보기 위해 TV 켜기, 앰프 켜고 모드 바꾸기, DVD 플레이어 켜기, 조명 낮추기 등 여러 기기를 복잡하게 조작해야 합니다. 퍼사드 패턴은 이 모든 과정을 '영화 보기' 버튼 하나로 묶어주는 통합 리모컨과 같습니다. 사용자는 버튼 하나만 누르면 되고, 그 뒤에서 일어나는 복잡한 일들은 알 필요가 없습니다.

2. 왜 사용할까요?

  • 단순함: 복잡한 내부 구현을 몰라도, 퍼사드(Facade)가 제공하는 간단한 메서드만 호출하면 되므로 서브시스템을 매우 쉽게 사용할 수 있습니다.
  • 결합도 감소: 클라이언트는 퍼사드 객체에만 의존하고, 그 뒤에 있는 수많은 서브시스템 클래스들과는 직접적인 의존 관계가 없어집니다. 덕분에 내부 서브시스템이 변경되더라도 클라이언트 코드는 영향을 받지 않습니다.
  • 계층화된 구조: 시스템을 여러 계층으로 나눌 때, 각 계층의 진입점으로 퍼사드를 사용하면 깔끔한 구조를 만들 수 있습니다.

3. Java로 구현하는 방법

시나리오: 위에서 설명한 홈시어터 시스템을 직접 만들어 보겠습니다.

1단계: 복잡한 서브시스템 클래스들 준비

우리가 제어해야 할 복잡하고 다양한 기기들입니다.

Java
 
// 서브시스템 1: 앰프
class Amplifier {
    public void on() { System.out.println("앰프가 켜졌습니다."); }
    public void setDvd(DvdPlayer dvd) { System.out.println("앰프를 DVD 플레이어와 연결합니다."); }
    public void setSurroundSound() { System.out.println("앰프를 서라운드 사운드로 설정합니다."); }
    public void setVolume(int level) { System.out.println("볼륨을 " + level + "로 설정합니다."); }
    public void off() { System.out.println("앰프가 꺼졌습니다."); }
}

// 서브시스템 2: DVD 플레이어
class DvdPlayer {
    public void on() { System.out.println("DVD 플레이어가 켜졌습니다."); }
    public void play(String movie) { System.out.println("'" + movie + "'를 재생합니다."); }
    public void stop() { System.out.println("DVD를 멈춥니다."); }
    public void off() { System.out.println("DVD 플레이어가 꺼졌습니다."); }
}

// 서브시스템 3: 프로젝터
class Projector {
    public void on() { System.out.println("프로젝터가 켜졌습니다."); }
    public void wideScreenMode() { System.out.println("프로젝터를 와이드 스크린 모드로 설정합니다."); }
    public void off() { System.out.println("프로젝터가 꺼졌습니다."); }
}

2단계: 퍼사드(Facade) 클래스 구현

이 패턴의 핵심입니다. 퍼사드 클래스는 내부에 모든 서브시스템 객체들을 멤버 변수로 가지고, '영화 보기', '영화 끄기' 같은 단순화된 통합 메서드를 제공합니다.

Java
 
public class HomeTheaterFacade {
    // 퍼사드는 제어해야 할 모든 서브시스템을 알고 있다.
    private Amplifier amp;
    private DvdPlayer dvd;
    private Projector projector;

    public HomeTheaterFacade(Amplifier amp, DvdPlayer dvd, Projector projector) {
        this.amp = amp;
        this.dvd = dvd;
        this.projector = projector;
    }

    // '영화 보기' 버튼에 해당하는 통합 메서드
    // 복잡한 과정들을 순서대로 처리해준다.
    public void watchMovie(String movie) {
        System.out.println("=== 영화 볼 준비를 시작합니다... ===");
        projector.on();
        projector.wideScreenMode();
        amp.on();
        amp.setDvd(dvd);
        amp.setSurroundSound();
        amp.setVolume(5);
        dvd.on();
        dvd.play(movie);
    }

    // '영화 끄기' 버튼에 해당하는 통합 메서드
    public void endMovie() {
        System.out.println("\n=== 홈시어터를 종료합니다... ===");
        dvd.stop();
        dvd.off();
        amp.off();
        projector.off();
    }
}

3단계: 클라이언트 코드에서 퍼사드 사용하기

클라이언트는 이제 각 기기를 어떻게 켜고 설정하는지 알 필요 없이, 퍼사드가 제공하는 간단한 메서드만 호출하면 됩니다.

Java
 
public class Client {
    public static void main(String[] args) {
        // 1. 제어할 서브시스템 객체들을 생성
        Amplifier amp = new Amplifier();
        DvdPlayer dvd = new DvdPlayer();
        Projector projector = new Projector();

        // 2. 서브시스템들을 통합 관리하는 퍼사드 객체 생성
        HomeTheaterFacade homeTheater = new HomeTheaterFacade(amp, dvd, projector);

        // 3. 클라이언트는 '영화 보기' 메서드 하나만 호출하면 된다.
        homeTheater.watchMovie("인셉션");
        
        // 4. '영화 끄기' 메서드 하나만 호출하면 된다.
        homeTheater.endMovie();
    }
}

4. 퍼사드 패턴과 실제 사례

  • SLF4J (Simple Logging Facade for Java): 이름부터 'Facade'가 들어간 대표적인 예입니다. SLF4J는 Logback, Log4j, java.util.logging 등 다양한 로깅 구현체들의 복잡한 설정과 API를 Logger라는 단일한 인터페이스 뒤로 감춰줍니다. 개발자는 SLF4J의 간단한 API만 사용하면 되고, 실제 로깅 구현체는 자유롭게 교체할 수 있습니다.
  • 스프링 JdbcTemplate: 자바의 표준 데이터베이스 연결 API인 JDBC는 Connection, Statement, ResultSet 관리, 예외 처리 등 매우 복잡하고 반복적인 코드가 필요합니다. 스프링의 JdbcTemplate은 이 모든 복잡한 과정을 내부적으로 처리해주고, 개발자에게는 query(), update() 같은 단순한 메서드만 제공하는 퍼사드 역할을 합니다.

5. 문제 제시 및 답변 💡

문제: 컴퓨터를 켜는 과정을 생각해보세요. 전원 버튼을 누르면 내부적으로는 CPU가 활성화되고, 메모리가 자체 테스트를 수행하며, 하드 드라이브가 부팅 섹터를 읽는 등 여러 복잡한 과정이 순차적으로 일어납니다.

이 '컴퓨터 부팅 과정'을 퍼사드 패턴을 적용하여 설계해 보세요. 어떤 클래스들이 서브시스템이 되고, 퍼사드 클래스는 어떤 모습일까요?

답변:

퍼사드 패턴을 적용하기에 아주 좋은 예입니다.

  • 서브시스템:
    • CPU 클래스: freeze(), jump(), execute() 같은 메서드를 가짐.
    • Memory 클래스: load(bootAddress, data) 같은 메서드를 가짐.
    • HardDrive 클래스: read(bootSector) 같은 메서드를 가짐.
  • 퍼사드 클래스: ComputerFacade
    • 이 클래스는 내부에 CPU, Memory, HardDrive 객체를 가지고 있습니다.
    • start()라는 공개 메서드 하나를 제공합니다.
    • start() 메서드 내부에서 hardDrive.read(), memory.load(), cpu.jump(), cpu.execute() 같은 복잡한 서브시스템 메서드들을 정해진 순서대로 호출하여 부팅 과정을 처리합니다.

**사용자(클라이언트)**는 ComputerFacade 객체의 start() 메서드만 호출하면 되고, CPU, 메모리, 하드 드라이브의 복잡한 상호작용에 대해서는 전혀 신경 쓸 필요가 없습니다.

728x90
반응형