Adapter Pattern
Adapter 디자인 패턴의 필요성과 그 구조에 대해 알아봅니다.읽는데 4분 정도 걸려요.필요성
개발하다 보면, 이전에 개발했던 코드가 있는데, 새로 개발된 코드 사양에 맞게 변경시켜야 하는 상황이 많을 것이다.
마음같아선 새로 짜고 싶지만, dependency가 높은 코드나 배포가 진행된 코드의 경우 수정하는데 부담이 클 수 밖에 없다.
이런 경우에 오래된 코드를 새로운 코드 사양에 맞게 변형시켜줘야 할 필요성이 생기는데, 이 때 Adapter Pattern
을 사용하게 된다.
Adapter Pattern
예를 들어보기 위해 우리의 오랜 친구(?) Duck 시뮬레이터를 다시 불러와보자.
public interface Duck {
public void quack();
public void fly();
}
이제 새로운 동물을 시뮬레이터에 추가해보자. 바로 Turkey!
public interface Turkey {
public void gobble();
public void fly();
}
인터페이스를 보면 알겠지만, 울음 소리가 다르다.
따라서 기존에 많은 곳에서 사용되었던 quack() 메서드를 사용하는 곳에선 Turkey 인터페이스를 구현한 클래스의 인스턴스를 사용할 수가 없게된다.
이 경우 코드의 재사용성을 높이기 위해 Adapter
를 구현해서 사용하게 된다!
public class TurkeyAdapter implements Duck {
Turkey turkey;
public TurkeyAdapter(Turkey turkey) {
this.turkey = turkey;
}
public void quack() {
turkey.gobble();
}
public void fly() {
turkey.fly();
}
}
이렇게 TurkeyAdapter를 만들어주면 이 어댑터의 인스턴스는 Duck 취급을 받기에 quack() 메서드를 사용하는 부분에 이 인스턴스를 넣을 수 있다.
즉, Turkey를 Duck 처럼 사용할 수 있다는 뜻이다!
public class DuckSimulator {
public static void main(String[] args) {
MallardDuck duck = new MallardDuck(); // implement Duck
WildTurkey turkey = new WildTurkey(); // inplement Turkey
Duck turkeyAdapter = new TurkeyAdapter(turkey);
// 둘 다 가능.
duck.quack();
turkeyAdapter.quack(); // 내부적으로 turkey.gobble() 호출
}
}
IRL
실제로 Adapter Pattern이 적용되는 사례를 살펴보자.
java에서 일련의 객체를 나타낼 때 Iterator
를 많이들 사용하는데, 예전에 Iterator가 없을 때는 Enumerators
을 사용했다고 한다.
버전업이 되고 Iterator를 사용하는게 권장됐는데, legacy system에서는 아직도 Enumerators를 사용했기에 이를 강제할 수는 없었다.
따라서 이를 위해 EnumerationAdapter를 만들었다고 한다.
public interface Enumerators {
public boolean hasMoreElements();
public T nextElement();
}
public interface Iterator {
public boolean hasNext();
public T next();
public void remove();
}
public class EnumerationAdapter implements Iterator {
Enumerators enumerators;
public EnumerationAdapter(Enumerators enumerators) {
this.enumerators = enumerators;
}
public boolean hasNext() {
return enumerators.hasMoreElements();
}
public T next() {
return enumerators.nextElement();
}
public void remove() {
throw new UnsupportedOperationException();
}
}