헤드퍼스트 디자인패턴
- 본 책을 읽고 책의 내용을 간략하게 정리한 글입니다.
Chapter 7. 적응시키기 - 어댑터 패턴
객체지향 어댑터
- 어떤 인터페이스를 클라이언트에서 요구하는 형태로 적응시키는 역할
- 새로운 클래스의 인터페이스가 기존 코드의 인터페이스와 다를 경우, 그냥 연결해서 사용할 수 없다.
- 어댑터는 기존 시스템에서 사용하던 인터페이스를 구현해서, 새로운 클래스에 요구 내역을 전달할 수 있다.
어댑터 사용 방법 알아보기
오리 시뮬레이터 2
public class Duck {
public void quack();
public void fly();
}
Duck을 구현하는 물오리 클래스
public class MallardDuck implements Duck {
@Override
public void quack() {
System.out.println("꽥");
}
@Override
public void fly() {
System.out.println("날 수 있어요");
}
}
새로 등장한 칠면조
public interface Turkey {
public void gobble();
public void fly();
}
- Duck 객체가 부족해서 Turkey 객체를 대신 사용해야 하는 경우가 있다고 가정할 때, 인터페이스가 다르기 때문에 Turkey 객체를 바로 사용할 수 없다.
- 따라서 Duck과 Turkey 인터페이스의 어댑터를 만들어준다.
public class TurkeyAdapter implements Duck {
Turkey turkey;
public TurkeyAdapter(Turkey turkey) {
this.turkey = turkey;
}
public void quack() {
turkey.gobble();
}
public void fly() {
for (int i = 0; i < 5; i++) {
// Duck 에 대응시키려고 5번 날아서 더 멀리 날도록 함
turkey.fly();
}
}
}
어댑터 패턴 알아보기
- 클라이언트는 타겟 인터페이스에 맞게 구현되어 있다.
- 어댑터는 타겟 인터페이스를 구현하며, 여기에는 어댑티(adaptee) 인스턴스가 들어 있다.
- 어댑티 인터페이스
- 위 예제에서 어댑티 인터페이스는 Turkey
어댑터 패턴 정의
- 어댑터 패턴은 특정 클래스 인터페이스를 클라이언트에서 요구하는 다른 인터페이스로 변환해주어, 인터페이스가 호환되지 않아 같이 쓸 수 없었던 클래스를 사용할 수 있게 도와준다.
어댑터 패턴 실전 적용하기
- Enumeration
| Enumeration | | ----------------- | | hasMoreElements() | | nextElement() |
- Iterator
| Iterator | | --------- | | hasNext() | | next() | | remove() |
Enumeration에서 remove()
메서드 처리하기
- Enumeration은 읽기 전용 인터페이스라서
remove()
에 해당하는 기능은 제공하지 않는다. - 어댑터에서 완벽하게 동작하는
remove()
메서드 구현 방법은 없다. - 그나마 런타임 예외를 던지는 게 좋은 방법이다.
EnumerationIterator 어댑터 코드 작성
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 UnsupportedOpperationException();
}
}