홈 씨어터를 구축한다고 생각해보자.
DVD 플레이어, 프로젝트, 자동 스크린, 서라운드 음향, 팝콘 기계까지 갖춘 시스템을 구성했다고 하자. 그러면 각각에 해당하는 클래스가 필요하다. 그리고 영화를 보기 위해서 각각의 클래스를 조종하는 일련의 과정이 필요하다.
popper.on();
popper.pop();
lights.dim(10);
screen.down();
.
.
.
이런 상황에서 영화가 끝날 땐 이 상황을 반대로 해야할 수도 있고 작동 방법이 바뀌게 되면 해당 코드를 고쳐야 하는 문제가 생긴다.
이 때 퍼사드 패턴
을 사용하면 간단한 인터페이스를 제공하여 복잡한 기능을 쉽게 사용하게 할 수 있다!
클라이언트에서 서브 시스템의 저수준 기능을 원한다면?
퍼사드를 사용하지 않고 서브 시스템 클래스를 사용하면 된다.
퍼사드에서 기능 추가 가능?
서브 시스템 단순하게 활용하는 것 외에 새로운 기능 구현 가능
한 서브 시스템에 대해 퍼사드를 한개만 만들 수 있는지?
원하는 만큼 만들 수 있다.
간단한 인터페이스 제공 외의 장점은?
클라이언트와 서브 시스템 분리 가능.
어댑터와 퍼사드 패턴의 차이점?
클래스를 감싼다는 점에서 비슷하지만 용도
가 다르다!
감싸는 클래스의 개수는 상관없음 -> 어댑터가 여러 클래스를 감쌀수도, 퍼사드가 하나의 클래스만 감쌀수도 있다.
어댑터 패턴 : 인터페이스를 클라이언트에서 필요로 하는 인터페이스로 변환
퍼사드 패턴 : 서브 시스템에 대한 간단한 인터페이스를 제공하기 위함
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();
}
}
public class HomeTheaterTestDrive {
public static void main(String[] args) {
Amplifier amp = new Amplifier("Amplifier");
Tuner tuner = new Tuner("AM/FM Tuner", amp);
StreamingPlayer player = new StreamingPlayer("Streaming Player", amp);
CdPlayer cd = new CdPlayer("CD Player", amp);
Projector projector = new Projector("Projector", player);
TheaterLights lights = new TheaterLights("Theater Ceiling Lights");
Screen screen = new Screen("Theater Screen");
PopcornPopper popper = new PopcornPopper("Popcorn Popper");
HomeTheaterFacade homeTheater =
new HomeTheaterFacade(amp, tuner, player,
projector, screen, lights, popper);
homeTheater.watchMovie("Raiders of the Lost Ark");
homeTheater.endMovie();
}
}
어떤 서브 시스템의 일련의 인터페이스에 대한 통합된 인터페이스 제공 -> 퍼사드에서 고수준 인터페이스 정의 -> 서브 시스템 더 쉽게 이용 가능
퍼사드 패턴을 사용하면 최소 지식 원칙
이라는 객체 지향 원칙을 지킬 수 있다.
최소 지식 원칙
: 상호 작용하는 클래스의 개수와 상호 작용 방식을 주의하여 의존성을 낮춰야 한다.
다음 네 종류의 객체 메소드만 호출하자
public class Car {
Engine engine;
public void updateDashboadDisplay() {}
public void start(Key key) {
Doors doors = new Doors();
// 매개 변수로 전달된 객체
boolean authorized = key.truns();
if (authorized) {
// 객체의 구성요소
engine.start();
// 객체 내의 메소드
updateDashboardDisplay();
// 직접 생성한 객체
doors.lock();
}
}
}
데메테르 법칙과의 관계?
완전히 똑같은 말.
최소 지식 원칙의 단점?
래퍼 클래스를 많이 만들어서 시스템의 복잡도가 올라가거나 개발 시간이 늘어나고 성능이 떨어질 수 있다.
퍼사드를 이용해서 클라이언트와 서브 시스템과의 관계를 끊어놨기 때문에 클라이언트와 서브 시스템은 각각 퍼사드와만 상호 작용할 수 있다.
-> 상호 작용하는 객체 최소화