참고: JAVA 언어로 배우는 디자인 패턴 입문
프로그램 세계에서 이미 제공되어 있는 것을 그대로 사용할 수 없을 때, 필요한 형태로 교환하고 사용하는 일이 자주 있습니다.
'이미 제공되어 있는 것' 과 '필요한 것' 사이의 '차이'를 없애주는 디자인 패턴을 Adapter패턴 이라고 합니다. (Wrapper 패턴으로 불리기도 합니다.)
Adapter 패턴에는 두가지 종류가 있습니다.
- 클래스에 의한 Adapter 패턴 (상속을 사용한 Adapter 패턴)
- 인스턴스에 의한 Adapter 패턴 (위임을 사용한 Adapter 패턴)
1. 클래스에 의한 Adapter 패턴 (상속을 사용한 Adapter 패턴)
public interface Print {
public abstract void printWeak();
public abstract void printStrong();
}
public class Banner {
private String string;
public Banner(String string) {
this.string = string;
}
public void showWithParen() {
System.out.println( "(" + string + ")" );
}
public void showWithAster() {
System.out.println( "*" + string + "*" );
}
}
public class PrintBanner extends Banner implements Print {
public PrintBanner(String string) {
super(string);
}
@Override
public void printWeak() {
showWithParen();
}
@Override
public void printStrong() {
showWithAster();
}
}
public class Main {
public static void main(String[] args) {
Print p = new PrintBanner("Hello");
p.printWeak();
p.printStrong();
}
}
Banner 클래스에는 문자열을 괄호로 묶어서 표시하는 showWithParen 메소드와 문자열 전후에 *를 붙여 showWithAster 메소드가 준비되어 있습니다. 이 Banner 클래스가 '이미 제공되어 지는것' 입니다.
Print 인터페이스에는 문자열을 느슨하게 표시하기 위한 printWeak 메소드와 문자열을 강하게 표시하기 위한 printStrong 메소드가 선언되어 있다고 가정합니다. 지금 하고 싶은 일은 Banner 클래스를 사용해서 Print 인터페이스를 충족시키는 클래스를 만드는 일입니다. 즉, 이미 제공되어지는 것을 필요한 것으로 교환시켜 주는 어댑터를 만드는 일입니다.
PrintBanner 클래스가 어댑터의 역할을 담당합니다. 이 클래스는 제공되어 있는 Banner 클래스를 상속해서, 필요로 하는 Print 인터페이스를 구현합니다.
Main 클래스 내에서 PrintBanner의 인스턴스를 Print 인터페이스형의 변수로 대입한 것에 주의해야 합니다. 이 Main은 어디까지나 Print라는 인터페이스를 사용해서 프로그래밍 하고 있습니다.
2. 인스턴스에 의한 Adapter 패턴 (위임을 사용한 Adapter 패턴)
public class PrintBanner extends Print {
private Banner banner;
public PrintBanner(String string) {
this.banner = new Banner(string);
}
@Override
public void printWeak() {
banner.showWithParen();
}
@Override
public void printStrong() {
banner.showWithAster();
}
}
이번에는 위임을 사용합니다. Print는 인터페이스가 아니고 추상클래스 입니다. Banner 클래스를 이용해서 Print 클래스와 동일한 메소드를 갖는 클래스를 실현하려는 것입니다.
PrintBanner 클래스는 banner 필드에서 Banner 클래스의 인스턴스를 가집니다. 이 인스턴스는 PrintBanner 클래스의 생성자에서 생성합니다. 그리고 printWeak 및 printStrong 메소드에서는 banner 필드를 매개로 showWithParen, showWithAster 메소드를 호출합니다. 필드를 경유해서 호출하고 있습니다. 즉 위임을 하고 있습니다.
Q. 메소드가 필요하면 그것을 프로그래밍하면 되지 왜 Adapter 패턴이 필요한 것일까?
Q. Adapter 패턴은 어떤 경우에 사용하는 것일까요?
Adapter 패턴은 기존의 클래스를 개조해서 필요한 클래스를 만듭니다. 이 패턴으로 필요한 메소드를 발빠르게 만들 수 있습니다. 만약 버그가 발생해도 기존의 클래스(Adapter의 역할)에는 버그가 없으므로 Adapter 역할의 클래스를 중점적으로 조사하면 되고, 프로그램 검사도 상당히 쉬워집니다.
이미 만들어진 클래스를 새로운 인터페이스(API)에 맞게 개조 시킬 때는 당연히 Adapter패턴을 사용해야 합니다. 그러나 실제 우리가 새로운 인터페이스(API)에 맞게 개조시킬 때는 기존 클래스의 소스를 바꾸어서 '수정' 하려고 생각합니다. '이것을 조금 바꾸면 분명 작업은 끝이다' 라고 생각하기 쉽습니다. 그러나 그렇게 하면 동작 테스트가 이미 끝난 기존의 클래스를 수정한 후에 다시 한번 테스트해야 합니다. Adapter 패턴은 기존의 클래스를 전혀 수정하지 않고 목적한 인터페이스(API)에 맞추려는 것입니다. 또한 Adapter 패턴에서는 기존 클래스의 소스 프로그램이 반드시 필요한 것은 아닙니다. 기존 클래스의 사양만 알면 새로운 클래스를 만들 수 있습니다.