어댑터 & 파사드 패턴
어댑터 & 파사드 패턴
🧤 어댑터 & 파사드 패턴이란
어댑터 패턴
한 클래스의 인터페이스를 클라이언트에서 사용하고자하는 다른 인터페이스로 변환한다. 어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다.
파사드 패턴
어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공한다. 퍼사드에서 고수준 인터페이스를 정의하기 때문에 서브시스템을 더 쉽게 사용할수 있다.
🔧 어댑터 패턴의 이해
🚀 활용 예시
칠면조를 오리로 변환하기 위해서는… (둘다 새이긴 하니까)
Duck 객체가 모자라서 Turkey 객체를 대신 사용해야 하는 상황이라고 해보자. 인터페이스가 다르기 때문에 Turkey객체를 바로 사용할 수는 없다. 어댑터를 만들어 보자.
오리 인터페이스
1
2
3
4
5
public interface Duck {
public void quack(); //오리는 꽥꽥
public void fly();
}
오리 구현체
1
2
3
4
5
6
7
8
9
10
11
public class MallardDuck implements Duck {
@Override
public void quack() {
System.out.println("Quack");
}
@Override
public void fly() {
System.out.println("I'm flying");
}
}
칠면조 인터페이스
1
2
3
4
5
public interface Turkey {
public void gobble(); //칠면조는 이렇게 운다..
public void fly();
}
칠면조 구현체
1
2
3
4
5
6
7
8
9
10
11
public class WildTurkey implements Turkey {
@Override
public void gobble() {
System.out.println("Gobble gobble");
}
@Override
public void fly() {
System.out.println("I'm flying a short distance");
}
}
어댑터 구현
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class TurkeyAdapter implements Duck { //오리인터페이스를 구현한다.
Turkey turkey;
public TurkeyAdapter(Turkey turkey) { //생성자에서 칠면조를 받는다.
this.turkey = turkey;
}
@Override
public void quack() {
turkey.gobble(); //변환 작업
}
@Override
public void fly() {
turkey.fly();
}
}
실행
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class DuckTestDrive {
public static void main(String[] args) {
MallardDuck duck = new MallardDuck();
WildTurkey turkey = new WildTurkey();
Duck turkeyAdapter = new TurkeyAdapter(turkey);
System.out.println("The turkey says...");
turkey.gobble();
turkey.fly();
System.out.println("The Duck says...");
testDuck(duck);
System.out.println("The TurkeyAdapter says...");
testDuck(turkeyAdapter);
}
public static void testDuck(Duck duck) {
duck.quack();
duck.fly();
}
}
🚌 정리
- 클라이언트 ->
request()
-> 어댑터 -translatedRequest()
-> 어댑티. - 클라이언트는 타겟 인터페이스에 맞게 구현, 어댑터는 타겟 인터페이스를 구현하며, 어댑티 인스턴스가 들어있음.
🗿 파사드 패턴의 이해
패턴을 사용할때는 항상 패턴이 어떤 용도로 쓰이는지를 잘 알아둬야 한다. 퍼사드 패턴은 단순화된 인터페이스를 통해서 서브시스템을 더 쉽게 사용할 수 있도록 하기위한 용도로 쓰인다.
💿 DVD영화를 보려고하면..
홈씨어터로 퍼사드 패턴을 구현해보자. 전선과 프로젝터를 설치하고, 각 장치들을 케이블로 연결하고 등등 여러 인터페이스들이 나열되어 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1.팝콘 기계를켠다.
2.팝콘 튀기기 시작.
3.전등을 어둡게 조절
4.스크린을 내린다.
..
..
12.DVD 플레이어를 켠다
13.DVD를 재생한다.
poper.on();
poper.pop();
light.dim(10)
screen.down();
.....
dvd.on();
dvd.play(movie);
너무 복잡하다… 버튼하나로 모든 세팅이 끝나게 할 수는 없을까?
- 이런 경우에 퍼사드를 사용하면 된다.
- 퍼사드 패턴은 인터페이스를 단순화시키기 위해서 인터페이스를 변경한다.
- 통합 인터페이스를 제공하는 퍼사드 클래스를 구현함으로써 복잡한 시스템을 훨씬 쉽게 사용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class HomeTheaterFacade { //영화 세팅의 모든것이 담겨있는 파사드 객체
Amplifier amp;
Tuner tuner;
Dvdplayer dvd;
CdPlayer cd;
Projector projector;
TheaterLights lights;
Screen screen;
PopcornPopper popper;
public HomeTheaterFacade(Amplifier amp,
Tuner tuner,
DvdPlayer dvd,
CdPlayer cd,
Projector projector,
Screen screen,
TheaterLights lights,
PopcornPopper popper) {
this.amp = amp;
this.tunner = tuner;
this.dvd = dvd;
this.cd = cd;
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.setDvd(dvd);
amp.setsurroundSound();
amp.setVolume(5);
dvd.on();
dvd.play(movie);
}
public void endMovie() { //끌 때도 마찬가지!
System.out.println("Shutting movie theater down...");
popper.off();
lights.on();
screen.up();
projector.off();
amp.off();
dvd.stop();
dvd.eject();
dvd.off();
}
}
public class HomeTheaterTestDrive {
public static void main(String[] args) {
// instantiate components here
HomeTheaterFacade homeTheater =
new HomeTheaterFacade(amp, tuner, dvd, cd, projector, screen, lights, popper);
homeTheater.watchMovie("타짜");
homeTheater.endMovie();
}
}
💰 최소지식원칙
‘정말 친한 친구하고만 얘기하라’
어떤 객체든 그 객체와 상호작용을 하는 클래스의 개수에 주의해야 하며, 그런 객체들과 어떤 식으로 상호작용을 하는지에도 주의를 기울여야 한다는 뜻이다.
⚙️ 최소지식원칙을 지키는 방법
어떻게 하면 여러 객체하고 인연을 맺는 것을 피할 수 있을까 어떤 메소드에서든지 아래와 같은 네 종류의 객체의 메소드
만을 호출하면 된다.
- 객체 자체
- 메소드에 매개변수로 전달된 객체
- 그 메소드에서 생성하거나 인스턴스를 만든 객체
- 그 객체에 속하는 구성요소
🥊 활용 예시
원칙을 따르지 않은 경우
1
2
3
4
public float getTemp(){
Thermometer thermometer=station.getThermometer(); // station 오로부터 thermometer라는 객체를 받은다음
return thermometer.getTemperature(); //그 갹체의 getTemperature()메소드를 직접 호출.
}
원칙을 따르는 경우
1
2
3
4
public float getTemp(){
return station.getTemperature(); // Station 클래스에 thermometer에 요청을 해주는 메소드를 추가
// 이렇게 하면 의존해야 하는 클래스의 개수를 줄일수 있다.
}
자동차로 예시를 들면
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Car {
Engine engine; //이 클래스의 구성요소. 이 구성요소의 메소드는 호출해도 된다.
public Car() {
}
public void start(Key key) { // 매개변수로 전달된 객체의 메소드는 호출해도 된다.
Doors doors = new Doors(); //새로운 객체 생성. 이 객체의 메소드는 호출해도 된다.
boolean authorized = key.turns(); //매개변수로 전달된 객체의 메소드는 호출해도 된다.
if (authorized) {
engine.start(); // 이 객체의 구성요소의 메소드는 호출해도 된다.
updateDashboardDisplay(); // 객체 내에 있는 메소드는 호출해도 된다.
doors.lock(); //직접 생성하거나 인스턴스를 만든 객체의 메소드는 호출해도 된다.
}
}
public void updateDashboardDisplay() {
}
}
This post is licensed under CC BY 4.0 by the author.