변혁적인 삶

[SW공학 | 디자인패턴] 3. 퍼사드 패턴(Facade Pattern) 본문

SW공학/디자인패턴

[SW공학 | 디자인패턴] 3. 퍼사드 패턴(Facade Pattern)

revolutionarylife 2024. 11. 1. 13:31
반응형

🏢 [SW공학 | 디자인패턴] 3. 퍼사드 패턴(Facade Pattern)

목차

  • 퍼사드 패턴 개요
  • 퍼사드 패턴의 필요성
  • 퍼사드 패턴의 구조
  • 퍼사드 패턴 예제
  • 퍼사드 패턴의 장점과 단점
  • 마무리

퍼사드 패턴 개요

안녕하세요! 오늘은 소프트웨어 설계에서 복잡한 시스템을 단순화하는 퍼사드 패턴(Facade Pattern)에 대해 알아보겠습니다. 퍼사드 패턴은 구조 패턴(Structural Pattern) 중 하나로, 여러 서브시스템의 복잡한 내부 구조를 감추고, 단순한 인터페이스를 제공하여 사용자가 쉽게 접근할 수 있도록 해줍니다.

마치 큰 빌딩의 정문(퍼사드)이 다양한 방과 복잡한 설비들을 감추고 외부 사람에게는 깔끔하고 간편한 모습만 보여주는 것처럼, 퍼사드 패턴은 클라이언트가 쉽게 접근할 수 있도록 복잡한 서브시스템에 대한 단순화된 접근을 제공합니다.


퍼사드 패턴의 필요성

대규모 애플리케이션에서는 여러 서브시스템이 협력하여 다양한 기능을 제공합니다. 하지만 이러한 시스템의 복잡한 구조는 클라이언트가 사용하기 어려울 수 있습니다. 퍼사드 패턴은 이런 복잡성을 감추고, 서브시스템에 대한 단일화된 접근 인터페이스를 제공하여 사용자 경험을 개선합니다.

예를 들어, 클라이언트가 특정 기능을 사용하려고 할 때 서브시스템 간의 복잡한 의존성을 일일이 처리하지 않고, 퍼사드 클래스 하나만 호출하면 필요한 기능이 실행되도록 할 수 있습니다. 이를 통해 클라이언트는 복잡한 로직을 알 필요 없이 쉽게 원하는 작업을 수행할 수 있습니다.


퍼사드 패턴의 구조

퍼사드 패턴은 퍼사드(Facade)와 여러 서브시스템(Subsystem)들로 구성됩니다. 퍼사드는 클라이언트가 접근하기 쉬운 인터페이스를 제공하고, 내부에서 서브시스템과 상호작용하여 복잡한 요청을 처리합니다.

  • 클라이언트(Client): 퍼사드를 통해 기능을 요청하는 사용자나 코드.
  • 퍼사드(Facade): 복잡한 서브시스템을 감추고 단순한 인터페이스를 제공하는 클래스.
  • 서브시스템(Subsystem): 실제로 기능을 수행하며, 퍼사드가 요청을 중개하여 상호작용하는 내부 구성 요소.

퍼사드 패턴 클래스 다이어그램

이 다이어그램에서 각 클래스는 퍼사드 패턴의 역할을 다음과 같이 수행합니다:

  1. Client:
    • 클라이언트는 WashingMachine 클래스의 기능을 호출하여 세탁을 시작합니다. 이 클래스는 퍼사드 패턴에서 시스템을 사용하는 외부 사용자를 의미합니다.
  2. WashingMachine (Facade):
    • WashingMachine 클래스는 퍼사드 역할을 수행합니다. 이 클래스는 startWashing()와 같은 단순화된 메서드를 제공하여 클라이언트가 세탁을 시작할 수 있도록 합니다. 내부적으로는 Washing, Rinsing, Spinning 클래스들을 호출하여 복잡한 세탁 프로세스를 관리합니다.
    • WashingMachine 클래스는 클라이언트에게 복잡한 내부 메서드들을 감추고 단일화된 인터페이스를 제공합니다.
  3. Washing, Rinsing, Spinning (Subsystems):
    • 각각의 클래스는 세탁기 내부의 특정 기능을 담당하는 서브시스템입니다.
    • Washing: 세탁 기능을 담당하며 wash() 메서드를 통해 실제 세탁을 수행합니다.
    • Rinsing: 헹굼 기능을 담당하며 rinse() 메서드를 통해 헹굼을 수행합니다.
    • Spinning: 탈수 기능을 담당하며 spin() 메서드를 통해 탈수를 수행합니다.
    • WashingMachine 퍼사드 클래스는 이 서브시스템들과 상호작용하여 클라이언트의 요청을 처리합니다.

요약하자면, 이 다이어그램은 퍼사드 패턴에서 WashingMachine이 퍼사드 역할을 하여 클라이언트가 복잡한 세탁, 헹굼, 탈수 과정을 신경 쓰지 않고 간단히 세탁을 시작할 수 있도록 돕는 구조를 보여줍니다.


퍼사드 패턴 예제

예제 1. Washing Machine(세탁기)

퍼사드 패턴의 첫번째 예로, 위에서 설명한 세탁기 예시로 설명해보겠습니다. 먼저 예시 코드부터 보여드리겠습니다.

// 서브시스템 클래스들
class Washing {
    public void wash() {
        System.out.println("세탁을 시작합니다.");
    }
}

class Rinsing {
    public void rinse() {
        System.out.println("헹굼을 시작합니다.");
    }
}

class Spinning {
    public void spin() {
        System.out.println("탈수를 시작합니다.");
    }
}

// 퍼사드 클래스
class WashingMachine {
    private Washing washing;
    private Rinsing rinsing;
    private Spinning spinning;

    public WashingMachine() {
        this.washing = new Washing();
        this.rinsing = new Rinsing();
        this.spinning = new Spinning();
    }

    public void startWashing() {
        washing.wash();
        rinsing.rinse();
        spinning.spin();
        System.out.println("세탁이 완료되었습니다.");
    }
}

// 클라이언트 클래스
public class Client {
    public static void main(String[] args) {
        WashingMachine washingMachine = new WashingMachine();
        washingMachine.startWashing();
        // 출력:
        // 세탁을 시작합니다.
        // 헹굼을 시작합니다.
        // 탈수를 시작합니다.
        // 세탁이 완료되었습니다.
    }
}

코드 설명

  1. 서브시스템 클래스
    • Washing, Rinsing, Spinning 클래스는 각각 세탁, 헹굼, 탈수 기능을 수행합니다. 이 클래스들은 세탁기의 내부 구성 요소로, 특정 작업을 수행하는 메서드를 가지고 있습니다.
  2. WashingMachine (Facade)
    • WashingMachine 클래스는 퍼사드 역할을 하여 클라이언트에게 단순화된 startWashing() 메서드를 제공합니다. 이 메서드를 호출하면 내부적으로 Washing, Rinsing, Spinning 클래스의 메서드가 순차적으로 호출되어 세탁 과정이 시작됩니다.
    • 클라이언트는 각 서브시스템의 세부 사항을 몰라도 startWashing() 메서드 하나만 호출하여 전체 세탁을 수행할 수 있습니다.
  3. Client
    • 클라이언트는 WashingMachine 클래스의 인스턴스를 생성하고 startWashing() 메서드를 호출하여 세탁을 시작합니다.
    • 클라이언트 입장에서는 내부적으로 어떤 과정이 수행되는지 알 필요 없이, 단순히 startWashing() 호출로 세탁을 완료할 수 있습니다.

장점

이 예제에서 퍼사드 패턴의 장점은 다음과 같습니다:

  • 단순화된 인터페이스: 클라이언트는 복잡한 세탁, 헹굼, 탈수 과정을 알 필요 없이, startWashing() 메서드 하나로 전체 과정을 수행할 수 있습니다.
  • 유지보수성 향상: 만약 세탁기의 내부 세탁 방식이나 순서가 변경되더라도 클라이언트 코드를 수정할 필요가 없습니다. 퍼사드 클래스에서만 변경을 관리하면 됩니다.
  • 캡슐화된 서브시스템: WashingMachine 퍼사드 클래스가 서브시스템을 감추기 때문에 클라이언트는 세부 사항을 몰라도 됩니다.

이처럼 퍼사드 패턴은 복잡한 시스템을 단일 인터페이스로 감싸서 클라이언트가 쉽게 사용할 수 있도록 도와주는 역할을 합니다.


예제 2. Home theater(홈 시어터)

퍼사드 패턴의 두번째 예로, 클라이언트가 홈 시어터 시스템을 사용하고자 하는 경우를 가정해 보겠습니다. 홈 시어터에는 여러 서브시스템(예: TV, 스피커, 조명, 블루레이 플레이어)이 있으며, 퍼사드 클래스는 이 모든 서브시스템을 제어하여 간단한 ‘영화 보기’ 기능을 제공합니다.

퍼사드 패턴 구성 요소

  1. Client (클라이언트)
    • 클라이언트는 HomeTheaterFacade 클래스의 watchMovie() 메서드를 호출하여 홈 시어터를 작동합니다. 클라이언트는 복잡한 세부 사항을 몰라도 간단히 영화를 재생할 수 있습니다.
  2. HomeTheaterFacade (퍼사드 클래스)
    • HomeTheaterFacade 클래스는 홈 시어터 시스템의 퍼사드 역할을 합니다.
    • 클라이언트가 watchMovie() 메서드를 호출하면 내부적으로 TV를 켜고, 사운드 시스템 볼륨을 설정하며, 블루레이 플레이어를 작동하여 영화를 재생하는 일련의 작업을 처리합니다.
    • 퍼사드 클래스는 클라이언트에게 단순화된 인터페이스(watchMovie())를 제공하여 서브시스템의 복잡한 동작을 감추고, 사용자가 쉽게 접근할 수 있도록 돕습니다.
  3. 서브시스템 클래스들 (TV, SoundSystem, BluRayPlayer)
    • TV, SoundSystem, BluRayPlayer 클래스는 각각 홈 시어터의 구성 요소들로서, 개별 기능을 수행하는 서브시스템입니다.
    • TV 클래스는 TV를 켜고 끄는 기능을 제공합니다.
    • SoundSystem 클래스는 볼륨을 설정하는 기능을 제공합니다.
    • BluRayPlayer 클래스는 블루레이 디스크를 재생하는 기능을 제공합니다.
    • 각각의 서브시스템 클래스는 독립적으로 특정 작업을 수행하며, HomeTheaterFacade 퍼사드 클래스가 이 서브시스템들을 조합하여 클라이언트 요청을 처리합니다.
// 서브시스템 예제
// TV 클래스는 TV를 켜고 끄는 on()과 off() 메서드를 제공합니다.
class TV {
    void on() { System.out.println("TV 켜기"); }
    void off() { System.out.println("TV 끄기"); }
}

//SoundSystem 클래스는 setVolume(int level) 메서드를 통해 볼륨을 조절합니다.
class SoundSystem {
    void setVolume(int level) { System.out.println("볼륨 조정: " + level); }
}

//BluRayPlayer 클래스는 play() 메서드를 통해 블루레이 디스크를 재생하는 기능을 담당합니다.
class BluRayPlayer {
    void play() { System.out.println("블루레이 재생"); }
}
//각각의 서브시스템 클래스는 개별 기능을 수행하며, 클라이언트가 직접 사용하기엔 복잡할 수 있습니다.


// 퍼사드 클래스
// HomeTheaterFacade 클래스는 퍼사드 역할을 수행합니다.
class HomeTheaterFacade {
	//생성자를 통해 TV, SoundSystem, BluRayPlayer 서브시스템 객체를 초기화합니다.
    private TV tv;
    private SoundSystem sound;
    private BluRayPlayer bluRay;

    public HomeTheaterFacade(TV tv, SoundSystem sound, BluRayPlayer bluRay) {
        this.tv = tv;
        this.sound = sound;
        this.bluRay = bluRay;
    }
	
    //watchMovie() 메서드를 통해 TV를 켜고, 사운드 시스템의 볼륨을 설정하며, 블루레이 재생을 시작하는 일련의 과정을 처리합니다.
    //이 메서드는 tv.on(), sound.setVolume(5), bluRay.play()를 호출하여 복잡한 서브시스템 동작을 클라이언트에게 감추고, 단일화된 인터페이스를 제공합니다.
    public void watchMovie() {
        tv.on();
        sound.setVolume(5);
        bluRay.play();
        System.out.println("영화 시작!");
    }
}

// 클라이언트 코드
//Client 클래스는 HomeTheaterFacade 객체를 생성하고 watchMovie() 메서드를 호출하여 홈 시어터 기능을 시작합니다.
//클라이언트는 서브시스템의 세부 사항을 몰라도 HomeTheaterFacade의 단일 메서드로 전체 동작을 간단하게 수행할 수 있습니다.
public class Client {
    public static void main(String[] args) {
        TV tv = new TV();
        SoundSystem sound = new SoundSystem();
        BluRayPlayer bluRay = new BluRayPlayer();
        HomeTheaterFacade homeTheater = new HomeTheaterFacade(tv, sound, bluRay);

        homeTheater.watchMovie(); // 출력: TV 켜기 -> 볼륨 조정: 5 -> 블루레이 재생 -> 영화 시작!
    }
}

출력 결과

TV 켜기
볼륨 조정: 5
블루레이 재생
영화 시작!

이 예제에서 `HomeTheaterFacade` 클래스는 여러 서브시스템을 제어하여 클라이언트가 하나의 메서드로 홈 시어터를 쉽게 작동할 수 있도록 합니다.

장점

이 예제에서 퍼사드 패턴의 장점은 다음과 같습니다:

  • 단순화된 인터페이스: 클라이언트는 watchMovie() 메서드를 호출하는 것만으로 홈 시어터를 작동할 수 있으며, 서브시스템의 복잡한 내부 구조를 알 필요가 없습니다.
  • 유지보수성 향상: 서브시스템의 동작이 바뀌더라도 클라이언트는 이를 알 필요가 없으며, 퍼사드 클래스에서만 변경을 처리하면 됩니다.
  • 캡슐화된 서브시스템: 퍼사드 클래스가 서브시스템의 내부를 감추기 때문에, 클라이언트는 서브시스템의 세부 사항을 몰라도 됩니다.

퍼사드 패턴의 장점과 단점

장점: 퍼사드 패턴은 서브시스템의 복잡성을 숨기고 단순한 인터페이스를 제공하여 클라이언트가 쉽게 사용할 수 있도록 합니다. 이를 통해 코드의 가독성을 높이고, 유지보수가 용이해집니다.

단점: 서브시스템의 세부 기능을 모두 사용해야 할 경우 퍼사드가 제한적일 수 있으며, 서브시스템에 대한 완전한 제어가 어려울 수 있습니다. 또한, 서브시스템에 변경이 발생하면 퍼사드도 함께 수정이 필요해질 수 있습니다.


마무리

퍼사드 패턴은 복잡한 서브시스템을 감추고 단일화된 인터페이스를 제공하여 사용자가 시스템을 더 쉽게 활용할 수 있도록 돕습니다. 특히 대규모 시스템에서 코드의 가독성과 유지보수성을 높이고자 할 때 유용하게 적용할 수 있습니다. 퍼사드 패턴을 통해 복잡한 시스템에서도 간단하고 일관성 있는 인터페이스를 제공해 보세요! 🏢

반응형