퍼사드 패턴(Facade Pattern)
퍼사드 패턴은 서브 시스템에 있는 일련의 인터페이스를 통합 인터페이스로 묶어줍니다.
또한 고수준 인터페이스도 정의하므로 서브시스템을 더 편하게 쓸 수 있습니다.
위의 UML Class Diagram에서, Client 클래스는 Subsystem 클래스들에 직접적으로 접근하지 않습니다.
대신, Client는 간단한 인터페이스를 구현하고 Subsystem 클래스들 (Class1, Class2 및 Class3)을 통해 작동하는 Facade 클래스를 통해 작업합니다. Client는 단순한 Facade 인터페이스에만 의존하며 복잡한 서브시스템에 대해 독립적입니다.
여기서 중요한 포인트는 Facade 디자인 패턴을 사용하여 복잡한 서브시스템을 단순한 인터페이스로 감싸고, 클라이언트가 이 간소화된 인터페이스를 통해 상호작용할 수 있도록 하는 것입니다.
클라이언트는 직접적으로 서브시스템 클래스들과 상호작용할 필요 없이 "Facade" 클래스를 통해 간접적으로 서브시스템과 소통할 수 있습니다.
이는 시스템을 모듈화 하고, 클라이언트와 서브시스템 간의 결합도를 낮추어 시스템을 보다 유연하고 유지보수하기 쉽게 만드는 디자인 패턴 중 하나입니다.
예를 들어 봅시다.
영화를 보기위해 홈 시어터를 구축하고 싶습니다.
홈 시어터를 위해 여러 클래스가 필요하고, 이 클래스들이 서로 복잡하게 얽혀있다면 많은 인터페이스를 사용해야 할 것입니다.
클라이언트에서 영화를 보는 것을 구현한다고 가정해 보면, 클래스들을 전부 구성하고 하나하나 켜주어야만 합니다.
또, 추가적으로 라디오를 듣는다거나 영화가 끝난다거나 하는 일들이 추가되면 클라이언트의 코드는 매우 복잡해집니다.
이를 퍼사드 객체를 사용하여 클라이언트와 클래스들의 긴밀한 연결을 끊고, 클라이언트를 대신하여 복잡한 로직들을 구현할 수 있습니다.
Facade HomeTheaterFacade
public class HomeTheaterFacade {
Amplifier amp;
Tuner tuner;
StreamingPlayer player;
CdPlayer cd;
Projector projector;
TheaterLights lights;
Screen screen;
PopcornPopper popper;
public HomeTheaterFacade(Amplifier amp,
Tuner tuner,
StreamingPlayer player,
Projector projector,
Screen screen,
TheaterLights lights,
PopcornPopper popper) {
this.amp = amp;
this.tuner = tuner;
this.player = player;
this.projector = projector;
this.screen = screen;
this.lights = lights;
this.popper = popper;
}
public void watchMovie(String movie) {
System.out.println("Get ready to watch a movie...");
popper.on();
popper.pop();
lights.dim(10);
screen.down();
projector.on();
projector.wideScreenMode();
amp.on();
amp.setStreamingPlayer(player);
amp.setSurroundSound();
amp.setVolume(5);
player.on();
player.play(movie);
}
public void endMovie() {
System.out.println("Shutting movie theater down...");
popper.off();
lights.on();
screen.up();
projector.off();
amp.off();
player.stop();
player.off();
}
public void listenToRadio(double frequency) {
System.out.println("Tuning in the airwaves...");
tuner.on();
tuner.setFrequency(frequency);
amp.on();
amp.setVolume(5);
amp.setTuner(tuner);
}
public void endRadio() {
System.out.println("Shutting down the tuner...");
tuner.off();
amp.off();
}
}
클라이언트는 퍼사드의 watchMovie(), endMoive() 등을 호출하여 똑같은 기능을 사용할 수 있습니다.
이를 통해 클라이언트는 서브 시스템과 긴밀한 연결을 끊고 분리될 수 있습니다.
디자인 원칙: 최소 지식 원칙
- 진짜 절친에게만 이야기해야 한다.
위 말은 시스템을 디자인할 때 어떤 객체든 그 객체와 상호작용을 하는 클래스의 개수와 상호작용 방식에 주의를 기울여야 한다는 뜻입니다.
최소 지식 원칙은 소프트웨어 모듈 사이의 결합도를 줄여서 코드의 품질을 높이는 것이 목표입니다.
이 원칙을 지키면, 여러 클래스가 복잡하게 얽혀있어 시스템의 한 부분을 변경했을 때 다른 부분까지 줄줄이 고쳐야하는 상황을 미리 방지할 수 있습니다.
퍼사드 클래스는 최소 지식 원칙을 다음과 같이 지켰습니다.
- 퍼사드 클래스는 클라이언트에게 단순하고 일관된 인터페이스를 제공합니다. 클라이언트는 퍼사드 클래스의 메서드만 호출하면 되며, 내부적으로 어떤 서브시스템이 있는지 알 필요가 없습니다.
- 퍼사드 클래스는 서브시스템과의 상호작용을 캡슐화하고, 클라이언트는 퍼사드를 통해서만 서브시스템과 소통합니다. 클라이언트는 서브시스템의 존재를 알 필요가 없고, 서브시스템의 변경이나 추가에 영향을 받지 않습니다.
- 클라이언트는 퍼사드를 통해 간접적으로 서브시스템과 상호작용합니다. 클라이언트는 퍼사드를 통해서만 필요한 기능을 수행하고, 서브시스템에 대한 직접적인 접근이 없습니다.
퍼사드 패턴을 사용하면 클라이언트는 더 적은 수의 클래스와만 상호작용하게 되므로 최소 지식 원칙을 적용하기 용이해집니다.
예를 들어, 아래 코드는 Station 이라는 인스턴스로부터 return 받은 객체의 메소드를 호출하여 최소 지식 원칙을 지키지 못하였습니다.
public float getTemp(){
Thermometer thermometer = station.getThermometer();
return thermometer.getTemperature();
}
이 문제를 해결하려면 Station 객체에 getTemperature() 메소드를 생성하는 것이 옳습니다.
왜냐하면 Temprature를 알려면 이 메소드는 Station을 알아야하고 Thermometer도 알아야 하기 때문입니다.
참고 자료
https://github.com/IT-Book-Organization/HeadFirst-DesignPattern/blob/main/Chapter_07/README.md
https://en.wikipedia.org/wiki/Facade_pattern
'ComputerScience > DesignPattern' 카테고리의 다른 글
[DesignPattern] 컴포지트 패턴(Composite Pattern) (0) | 2023.12.08 |
---|---|
[DesignPattern] 템플릿 메소드 패턴 (Template Method Pattern) (1) | 2023.12.08 |
[DesignPattern] Adapter Pattern (1) | 2023.12.08 |
[DesignPattern] Command Pattern (1) | 2023.12.07 |
[DesignPattern] Singleton Pattern (1) | 2023.12.07 |