어댑터 패턴
어댑터란?
•
한국에서 사용하던 플러그를 영국에서 사용하려고 한다면 플러그 모양을 바꿔주는 어댑터가 필요함
•
인터페이스를 다른 인터페이스 변환해주는게 바로 어댑터
•
객체지향에서는 기존 시스템에 변화 없이 인터페이스 규격이 맞지 않는 클래스를 변환하기 위해서 사용한다.
어댑터 패턴의 정의
객체 어댑터
어댑터 패턴은 특정 클래스 인터페이스를 클라이언트에서 요구하는 다른 인터페이스로 변환합니다.
인터페이스가 호환되지 않아 같이쓸 수 없던 클래스를 사용할 수 있게 도와줍니다.
•
어댑터 패턴은 여러 객체지향 원칙을 반영하고 있음
◦
어탭티를 새로 바뀐 인터페이스로 감쌀 때는 객체 구성을 사용
▪
이런 접근법은 어댑티의 모든 서브클래스에 어댑티를 쓸 수 있다는 장점
◦
클라이언트 특정 구현이 아닌 인터페이스에 연결
◦
타깃 인터페이스만 유지한다면 나중에 다른 구현을 추가하는것도 가능
객체 어댑터와 클래스 어댑터
클래스 어댑터
클래스 어댑터 패턴을 쓰려면 다중 상속이 필요한데 자바에서는 다중 상속이 불가능하므로 별도로 언급하지 않음
•
클래스 어댑티는 특정 클래스에만 어댑타를 적용한다는 단점이 있지만 어댑티 전체를 다시 구현하지 않아도 된다는 장점이 있음
예제 - Enumeration을 Iterator에 적응시키기
•
타깃 인터페이스인 Iterator에 remove가 Enumeration에는 존재하지 않음
•
hasNext() 매소드는 hasMoreElements()와 연결됩니다.
•
next() 메소드는 nextElement() 메소드와 연결됩니다.
어뎁터 디자인
remove() 메소드 처리하기
•
Enumeration는 remove()에 해당하는 기능을 제공하지 않음
◦
읽기 전용 인터페이스라 할 수 있음
•
때문에 해당 메서드 호출시 런타임 에러를 throw하도록 만들었음
public class EnumerationIterator implements Iterator<Object> {
Enumeration<?> enumeration;
public EnumerationIterator(Enumeration<?> enumeration) {
this.enumeration = enumeration;
}
public boolean hasNext() {
return enumeration.hasMoreElements();
}
public Object next() {
return enumeration.nextElement();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
Java
복사
퍼사드 패턴
홈시어터를 예시로
홈시어터를 보기 위해서 아래 일들을 진행해야 한다.
1. 팝콘 기계를 켠다
2. 팝콘을 튀기기 시작한다
3. 조명을 어둡게 조절한다
4. 스크린을 내린다
5. 프로젝터를 켠다
6. 프로젝터 입력을 스트리밍 플레이어로 설정한다.
7. 프로젝터를 와이드 스크린 모드로 전환한다.
8. 앰프를 켠다.
9. 앰프 입력을 스트리밍 플레이어로 설정한다.
10. 앰프를 서라운드 음향 모드로 전환한다.
11. 앰프 볼륨을 중간(5)으로 설정한다
12. 스트리밍 플레이어를 켠다
13. 영화를 재생한다.
Java
복사
아직 끝난게 아니고 추가적으로 할일 들이 남아있음
•
영화가 끝난다면 지금까지 했던걸 역순으로 처리해야할까?
•
라디오를 들을 때도 이렇게 복잡해야 할까?
•
시스템을 업그레이드 하면 작동 방법을 또 배워야 할까?
퍼사드 패턴을 이용하자
쓰기 쉬운 인터페이스를 제공하는 퍼사드를 구현함으로써 복잡한 시스템을 훨씬 편리하게 이용가능
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();
}
}
Java
복사
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();
}
}
Java
복사
퍼사드 패턴의 정의
퍼사드 패턴은 서브시스템에 있는 일련의 인터페이스를 통합 인터페이스 묶어줍니다.또한 고수준 인터페이스도 정의하므로 서브시스템을 더 편리하게 사용할 수 있습니다.
•
다른 패턴과 달리 퍼사드 패턴은 상당히 단순
•
그렇다고 해서 퍼사드 패턴이 별 볼 일 없는 패턴은 아님
•
퍼사드 패턴을 이용하면 클라이언트와 서브시스템간 서로 긴밀하게 연결된 객체지향 원칙을 준수하는데 도움이 됨
최소 지식 원칙(Principle of Least Knowledge)
최소 지식 원칙에 따르면 객체 사이의 상호작용은 될 수 있으면 아주 가까운 친구 사이에서만 허용하는 편이 좋다.
시스템을 디자인할 때 어떤 객체든 그 객체와 상호작용을 하는 클래스의 개수와 상호작용 방식에 주의를 기울여야 한다.
여러 클래스가 서로 복잡하게 의존하고 있다면 관리하기도 힘들고, 남들이 이해하기 어려운 불안정한 시스템이 만들어짐
친구를 만들지 않고 다른 객체에 영향력 행사하기
친구를 만들지 않는 4가지 가이드라인
•
객체 자신
•
메소드에 매채변수로 전달된 객체
•
메소드를 생성하거나 인스턴스를 만든 객체
•
객체에 속하는 구성 요소
public float getTemp() {
Thermometer thermeometer = station.getThermometer();
return thermometer;
}
Java
복사
원칙을 따르지 않는 경우
public float getTemp() {
return station.getTemperature();
}
Java
복사
원칙을 따르는 경우