이미 제공되어 있는 것을 그대로 사용할 수 없을 때, 필요한 형태로 교환하고 사용하는 일이 있다. 그대로 사용할 수 없는 것들을 필요한 형태로 교환해주는 디자인 패턴이 Adapter 패턴이다.
Adapter 패턴은 Wrapper 패턴이라고 불리기도 한다.
Adatper은 두 가지 종류가 있다.
Banner 클래스를 사용해서 Print 인터페이스를 충족시키는 클래스를 만든다고 생각해보자. 또한 Main 클래스에서 Banner를 사용한다고 생각하자.
PrintBanner 클래스가 어댑터의 역할을 담당한다. 이 클래스는 제공되어 있는 Banner 클래스를 상속해서, 필요로 하는 Print 인터페이스를 구현한다.
public class Main {
public static void main(String[] args) {
Print p = new PrintBanner("Hello");
p.printWeak();
p.printStrong();
}
}
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();
}
}
이제 Main클래스는 Banner를 실생활에서 어댑터를 끼워 사용한 것처럼 Print를 사용할 수 있다.
현재 Banner를 사용하여 Print를 사용하고 있지만, Main 클래스는 이를 전혀 모른채로 Print를 사용할 수 있다. 이 말은 Main 클래스를 변경하지 않고 PrintBanner의 클래스의 구현을 바꿀 수 있다는 뜻이다.
Print가 Interface가 아닌 Class라고 생각해보자. 자바에서는 이중상속이 불가능하기 때문에, PrintBanner는 Print와 Banner 모두 하위클래스로 가질 수 없다.
이전 예에서는 자신위 상위 클래스에서 상속한 메소드를 사용하여 호출하지만, 이번에는 필드를 경유해서 호출하자. 즉, 위임을 사용한다.
public abstract class Print {
public abstract void printWeak();
public abstract void printStrong();
}
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에 해당된다. 실제로 사용되어야하는 부분이다.
예제에서 Main에 해당된다. Target 역할의 메소드를 사용해서 일을 하는 부분이다.
예제에서 Banner에 해당된다. 그대로 사용할 수 없어, 바뀌어야 하는 부분을 의미한다. 이미 구현된 메소드들이 존재하는 부분이다.
예제에서 PrintBanner에 해당된다. Adapter 패턴에서 가장 중요한 부분이며, 이를 통해 Target의 역할을 어떻게든 만족시킨다. '상속'과 '위임'의 방식으로 구현이 가능하다.
Adapter 패턴은 기존의 클래스를 변환하여 Target 클래스를 사용할 수 있게 하기 때문에 빠르게 Target 클래스를 제작해 낼 수 있다. 또한 Client에서 이 Target을 사용하는 경우, 문제가 생긴다면 Adapter의 문제가 생긴 것이므로 버그를 빠르게 찾을 수 있을 것이다.
또한 소프트웨어 버전업에서도 이는 유용할 것이다. V1 버전에서 V2 버전으로 바꾸는데 필요한 API가 존재한다면, V1에서 사용했던 클래스를 Adapter 패턴을 이용하여 목적한 V2의 API로 변경하여 사용할 수 있을 것이다.
하지만, V1(Adaptee)과 V2(Target)가 너무나도 다르다면 당연히 사용할 수 없는 것을 유념하자. 100볼트의 전원으로 수돗물을 나오게 할 수는 없다.
출저 : Java 언어로 배우는 디자인 패턴 입문