한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환합니다. 어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있습니다. 요약하자면 어댑터는 한 인터페이스를 다른 인터페이스로 변환해주는 역할을 합니다.
어댑터를 어떻게 쓰는지 예제 코드를 통해서 살펴 보겠습니다.
Duck 인터페이스를 생성합니다.
public interface Duck {
void quack();
void fly();
}
Duck을 구현하는 MallardDuck(물오리) 클래스를 생성합니다.
public class MallardDuck implements Duck {
public void quack() {
System.out.println("Quack");
}
public void fly() {
System.out.println("I'm flying");
}
}
이제 새로 등장한 가금류인 Turkey인터페이스를 생성해 보겠습니다.
public interface Turkey {
void gobble();
void fly();
}
Turkey의 구현체인 WildTurkey를 생성합니다.
public class WildTurkey implements Turkey {
public void gobble() {
System.out.println("Gobble gobble");
}
public void fly() {
System.out.println("I'm flying a short distance");
}
}
Duck 객체가 모자라서 Turkey 객체를 대신 사용해야 하는 상황이라면 Turkey를 바로 사용할 수 없고 이때 Adapter가 필요합니다.
우선 적용시킬 형식의 인터페이스를 구현해야합니다. 여기서는 클라이언트가 Turkey객체를 쓰기 원하므로 클라이언트가 원하는 인터페이스를 구현합니다.
public class TurkeyAdapter implements Duck {
Turkey turkey;
public TurkeyAdapter(Turkey turkey) { // 01
this.turkey = turkey;
}
public void quack() { // 02
turkey.gobble();
}
public void fly() { // 03
for (int i = 0; i < 5; i++) {
turkey.fly();
}
}
}
01: 원래 형식의 객체에 대한 레퍼런스가 필요합니다. 여기에서는 생성자의 인자로 레퍼런스를 받아오는 작업을 처리합니다. 02, 03: Duck인터페이스에 있는 메소드들을 가금류의 특성에 맞게 모두 구현합니다.
import duck.Duck;
import duck.MallarDuck;
import turkey.WildTurkey;
public class DuckTestDrive {
public static void main(String[] args) {
MallarDuck duck = new MallarDuck();
WildTurkey turkey = new WildTurkey();
Duck turkeyAdapter = new TurkeyAdapter(turkey); // 01
System.out.println("The Tukey says...");
turkey.gobble();
turkey.fly();
System.out.println("\nThe duck says...");
testDuck(duck);
System.out.println("\nThe TurkeyAdapter says...");
testDuck(turkeyAdapter);
}
static void testDuck(Duck duck) {
duck.quack();
duck.fly();
}
}
01: Turkey를 TurkeyAdapater로 감싸서 Duck처럼 보이도록 합니다.
The Tukey says...
Gobble gobble
I'm flying a short distance
The duck says...
Quack
I'm flying
The TurkeyAdapter says...
Gobble gobble
I'm flying a short distance
I'm flying a short distance
I'm flying a short distance
I'm flying a short distance
I'm flying a short distance
테스트 결과를 보면 testDuck() 메서드에선느 오리하고 칠면조를 전혀 굽누하지 못하고 있습니다.
클라이언트가 어댑터를 사용하는 방법은
어댑터 패턴을 이용하면 호환되지 않는 인터페이스를 사용하는 클라이언트를 그대로 활용할 수 있습니다. 이렇게 함으로써 클라이언트와 구현된 인터페이스를 분리시킬 수 있으며,나중에 인터페이스가 바뀌더라도 그 변경은 어댑터에 캡슐화되기 때문에 클라이언트는 바뀔 필요가 없습니다.
하지만 대형 타겟 인터페이스를 구현해야 하는경우에는 고칠 코드가 엄청나게 많아질 수 도 있어서 고려할 사항이 많아지게 됩니다.