C++ - 퍼사드 패턴 (Facade Pattern)
Architecture & Design Pattern 전체 링크
참고
- 최소 지식 원칙
퍼사드 패턴 (Facade Pattern) - 구조 패턴
- 복잡한 시스템 또는 서브시스템을 단순화된 인터페이스로 제공하는 패턴
- 퍼사드에서 고수준 인터페이스를 정의하기 때문에 서브시스템을 더 쉽게 사용할 수 있다.
- 클라이언트가 시스템의 복잡성을 알 필요 없이 간단한 인터페이스를 통해 시스템에 접근할 수 있다.
구현
- Subsystem : 퍼사드가 제공하는 인터페이스를 구현하는 여러 클래스 또는 모듈의 집합
- Facade : 클라이언트와 상호작용하는 단일 인터페이스를 제공, 복잡한 시스템 또는 서브시스템을 캡슐화한다.
장점
- 클라이언트와 서브시스템과의 의존성과 결합도가 약해진다.
단점
- 특별한 요구사항이 있는 경우, 퍼사드가 복잡해진다. 이 경우 직접 서브시스템과 상호작용하는 것이 낫다.
- 인터페이스를 추가하기 때문에, 약간의 오버헤드가 발생한다.
홈 IOT 시스템
집 안에는 여러가지 IOT 기기가 존재한다.
더 복잡한 예시라면, 서로의 기기가 상호작용할 수도 있다.
class Speaker
{
public:
void setVolume(int v) { volume = v; }
private:
int volume;
};
class Light
{
public:
void on() { cout << "Light is On" << endl; }
void off() { cout << "Light is off" << endl; }
};
class Television
{
public:
void on() { cout << "TV is On" << endl; }
void off() { cout << "TV is off" << endl; }
void channelUp() { cout << "Channel Up" << endl; }
void channelDown() { cout << "Channel Down" << endl; }
void subtitleOn() { cout << "Subtitle On" << endl; }
void subtitleOff() { cout << "Subtitle Off" << endl; }
};
// 그 외 많은 클래스들...
만약 헐리우드 영화를 본다면 클라이언트는 직접 각 기기와 상호작용하여 메서드를 호출해야 한다.
cout << "Hollywood Movie Mode" << endl;
speaker->setVolume(10);
light->off();
tv->on();
tv->subtitleOn();
아래와 같이 여러 서브시스템과 클라이언트가 직접 상호작용을 하고 있는 상황이다.
퍼사드 패턴 적용
서브시스템의 메서드를 퍼사드에서 단순화된 인터페이스를 제공하도록 한다.
실제로 위의 경우와 같이 어떤 시스템은 수 많은 단순화된 시스템의 집합인 경우가 많다.
퍼사드가 서브시스템 사이에서 고수준의 인터페이스를 제공해서,
클라이언트가 서브시스템과의 의존성을 약화시키고, 서브시스템을 더 잘 사용할 수 있도록 한다.
퍼사드 구현은 최소 지식 원칙을 따른다.
클라이언트가 직접 서브시스템과 상호작용하지 않고, 퍼사드에서 클라이언트가 사용할 인터페이스를 제공한다.
헐리우드 영화를 보고 싶다면 클라이언트는 그냥 setHollywoodMovieMode만 호출하면 된다.
퍼사드가 제공하는 메서드에서 실제 작업은 서브시스템의 구성요소에 위임된다.
class HomeFacade
{
public:
HomeFacade(Speaker* s, Light* l, Television* t) : speaker(s), light(l), tv(t) {}
void setHollywoodMovieMode()
{
speaker->setVolume(10);
light->off();
tv->on();
tv->subtitleOn();
}
...
private:
Speaker* speaker;
Light* light;
Television* tv;
};
전체 코드는 다음과 같다.
#include <iostream>
#include <string>
using namespace std;
class Speaker
{
public:
void setVolume(int v) { volume = v; }
private:
int volume;
};
class Light
{
public:
void on() { cout << "Light is On" << endl; }
void off() { cout << "Light is off" << endl; }
};
class Television
{
public:
void on() { cout << "TV is On" << endl; }
void off() { cout << "TV is off" << endl; }
void channelUp() { cout << "Channel Up" << endl; }
void channelDown() { cout << "Channel Down" << endl; }
void subtitleOn() { cout << "Subtitle On" << endl; }
void subtitleOff() { cout << "Subtitle Off" << endl; }
};
// 그 외 많은 클래스들...
/* ---------------- Facade ---------------- */
class HomeFacade
{
public:
HomeFacade(Speaker* s, Light* l, Television* t) : speaker(s), light(l), tv(t) {}
void setHollywoodMovieMode()
{
speaker->setVolume(10);
light->off();
tv->on();
tv->subtitleOn();
}
void setSleepMode()
{
speaker->setVolume(0);
light->off();
tv->off();
}
private:
Speaker* speaker;
Light* light;
Television* tv;
};
int main()
{
Speaker* speaker = new Speaker();
Light* light = new Light();
Television* tv = new Television();
HomeFacade* hf = new HomeFacade(speaker, light, tv);
cout << "Hollywood Movie Mode" << endl;
hf->setHollywoodMovieMode();
cout << "\nSleep Mode" << endl;
hf->setSleepMode();
return 0;
}
어댑터 vs 퍼사드
어댑터 패턴
- 이미 존재하는 클래스의 인터페이스를 변경하지 않고, 클라이언트가 사용할 수 있도록 인터페이스를 변경한다.
→ 정해진 인터페이스에 대해 호환성 제공해야 하며, 이로 인해 인터페이스가 단순해지는 것은 아니다.
퍼사드 패턴
- 복잡한 시스템이나 서브시스템을 단순화된 인터페이스로 제공하는 패턴이다.
→ 인터페이스를 직접 개발하며, 단순화된 인터페이스를 제공하는 것이 목표다.
ClassDiagram.md
```mermaid
classDiagram
class Facade {
}
class Speaker {
volume
setVolume()
}
class Light {
on()
off()
}
class Television {
on()
off()
channelUp()
channelDown()
subtitleOn()
subtitleOff()
}
Client -- Facade
Facade -- Speaker
Facade -- Light
Light -- LED
Light -- Lamp
Facade -- Television
Television -- SetUpBox
Television -- AIAssistant
Facade -- AirConditioner
```