헤드퍼스트 디자인패턴 Chapter7 - 어댑터 패턴

헤드퍼스트 디자인패턴

  • 본 책을 읽고 책의 내용을 간략하게 정리한 글입니다.

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();
		}
	}
}

어댑터 패턴 알아보기

  1. 클라이언트는 타겟 인터페이스에 맞게 구현되어 있다.
  2. 어댑터는 타겟 인터페이스를 구현하며, 여기에는 어댑티(adaptee) 인스턴스가 들어 있다.
  3. 어댑티 인터페이스
    • 위 예제에서 어댑티 인터페이스는 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();
	}
}