자바 디자인 패턴 2 - Adapter

자바(JAVA)

1. Adapter 패턴은..

이미 구현되어 있는 코드가 있는데, 둘이 연결 좀 시켜주고 싶을 때가 있죠. 어떤 좋은 메쏘드가 있는데, 인자로 A라는 형식을 받습니다. 근데, 이미 구현되어 있는 코드에는 B라는 형식으로 구현되어 있습니다. 이럴 때, B를 A의 형식으로 바꿔주면 좋은 메쏘드를 써먹을 수 있습니다. Adapter 패턴은 어떤 오브젝트를 캐스팅이 불가능한 다른 클래스의 형태로 변환시켜주는 것입니다.

2. 예제
---------------Adapter Class --------------------
package ch02_adapter;
import java.util.Enumeration;
import java.util.Iterator;
public class IteratorToEnumeration implements Enumeration<String>{
   private Iterator<String> iter;
   public IteratorToEnumeration(Iterator<String> iter) {
      this.iter = iter;
   }
   public boolean hasMoreElements() {
      return iter.hasNext();
   }
   public String nextElement() {
      return iter.next();
   }
}

---------------뭔가 훌륭한 method를 가지고 있는 클래스 ------------
package ch02_adapter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
public class Test {
   public static void goodMethod(Enumeration<String> enu){
      while (enu.hasMoreElements()) {
         System.out.println(enu.nextElement());
      }
   }

   public static void main(String[] args) {
      List<String> list = new ArrayList<String>();
      list.add("이은결");
      list.add("Kevin parker");
      list.add("David Blaine");
      Enumeration<String> ite = new IteratorToEnumeration(list.iterator());
      Test.goodMethod(ite);
   }
}

우리가 최종적으로 쓰고자하는 것은 goodMethod() 입니다. 그 녀석은 인자로 Enumeration을 받고 있지요. 그러나 우리가 가지고 있는 것은 Iterator입니다. IteratorToEnumeration 클래스는 Iterator를 받아서 Enumeration 으로 변경시켜줍니다. AtoB의 형태를 가지는 Adapter는 A를 멤버변수로 가지고 B를 구현합니다. 소스코드에 색깔 칠해논 부분을 확인하세요.

3. Adapter를 구현하는 방법
위에서 소개된 방법은 "구성을 통한 방법" 또는 "위임을 통한 방법"입니다. Adapter 자체는 하는 일이 별로 없습니다. 내부적으로 멤버한테다가 일을 다 떠넘깁니다. 외관상 다른 형태로 변환가능하기 위한 것이지 어떤 일을 직접할려는 것은 아닙니다.

두번째 방법은 상속을 이용하는 방법입니다. A to B로 할 경우 A와 B를 둘다 구현하는 방법입니다. A와 B가 둘 다 인터페이스거나, 하나만 인터페이스일 때는 가능하지만, 둘 다 클래스일 경우에는 불가능하죠.
상속을 쓰는 것은 바람직하지 않습니다. "상속보다는 구성을 이용하라"는 원칙에 어긋납니다. 이 원칙에 대해서는 다음 설명드리죠.

세번째 방법은 Adapter 클래스를 만들지 않고 method로 만드는 방법입니다. 다음과 같은 코드는 위에서 구현한 것과 같은 효과를 보여주죠.

public static Enumeration<String> iteratorToEnumeration(final Iterator<String> iter) {
    return new Enumeration<String>() {
        public boolean hasMoreElements() {
            return iter.hasNext();
        }

        public String nextElement() {
            return iter.next();
        }
    };
}

눈치 빠르신 분들은 인자가 final이란 것을 보셨겠지요. final로 말뚝 박는 건 "변경 절대 불가!" 를 보장하는 겁니다. 메쏘드 안에서 Enumeration의 구현체가 인자로 받은 것을 사용하는데, 이런 경우에는 인자가 final 로 정의되어야 하며, 그렇지 않을 경우 컴파일시에 문제가 됩니다.
final로 정의한다는 것은 read-only라는 뜻입니다. 주의할 것은 read-only라는 게 다른 변수로 할당을 못한다는 것 뿐 내부의 메쏘드를 호출하지 못한다는 것은 아닙니다. (메쏘드 내부에서 iter = 따른거; 와 같이 할 수 없다는 거죠.) 즉 Immutable일 경우에는 진짜 read-only가 보장되지만, 위의 예제 같은 경우는 보장되지 않습니다. Immutable에 대한 얘기는 따로 다루겠습니다.

세번째 방법은 Adapter 패턴이라고 불리지는 않습니다. 그러나 하는 일이 똑같죠. 뭐라 불리건 말이 뭐가 중요합니까

4. JAVA API에 있는 Adapter
JDK에는 Adater를 구현해 논 게 없댑니다. AWT와 같은 UI관련된 애들 중에서 알아서 상속해서 쓰라는 인터페이스만 제공하고 있습니다.

위에서 소개한 세번째 방법을 통한 케이스는 무수히 많습니다. Integer, Float, Long 등과 같은 Wrapper 클래스들이 잔뜩 있지요.
Interger.valueOf(String) 은 String을 Integer로 바꿔주지요.
Posted by 녹두장군
TAG