아무거나

[Design Pattern] Adapter Pattern 본문

Java & Kotlin/Java

[Design Pattern] Adapter Pattern

전봉근 2019. 12. 7. 16:21
반응형

어댑터 패턴(Adapter Pattern)

클래스의 인터페이스를 사용자가 기대하는 다른 인터페이스로 변환하는 패턴 어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다.

어댑터 패턴은 이름대로 어댑터처럼 사용되는 패턴이다. 220V 를 사용하는 한국에서 쓰던 기기들을, 어댑터를 사용하면 110V 를 쓰는곳에 가서도 그대로 쓸 수 있다. 이처럼, 호환성이 없는 인터페이스 때문에 함께 동작할 수 없는 클래스들이 함께 작동하도록 해주는 패턴이 어댑터 패턴이라고 할 수 있겠다. 이를 위해 어댑터 역할을 하는 클래스를 새로 만들어야 한다.

기존에 있는 시스템에 새로운 써드파티 라이브러리가 추가된다던지, 레거시 인터페이스를 새로운 인터페이스로 교체하는 경우에 코드의 재사용성을 높일 수 있는 방법이 어댑터 패턴을 사용하는 것이다.

어댑터 패턴 예시 - 1

[요구사항]

  • 두 수에 대한 다음 연산을 수행하는 객체를 만들어라.

    • 수의 두 배의 수를 반환: twiceOf(Float):Float
    • 수의 반(1/2)의 수를 반환: halfOf(Float):Float
  • 구현 객체 이름은 Adapter로 결정

  • Math 클래스에서 두 배와 절반을 구하는 함수는 이미 구현 되어있음 [Math.java]

      package com.bkjeon.adapter;
    
      public class Math {
          // 두배
          public static double twoTime(double num) {return num * 2;}
    
          // 절반
          public static double half(double num) {return num / 2;}
      }
    

    위의 반환값은 double로 되어있기 때문에 요구사항의 반환값인 float과 맞지 않음을 알 수 있다.

Adapter 인터페이스 구현 및 implements할 AdapterImpl 클래스 생성 [Adapter.java]

package com.bkjeon.adapter;

public interface Adapter {
    public Float twiceOf(Float f);
    public Float halfOf(Float f);
}

[AdapterImpl.java]

package com.bkjeon.adapter;

public class AdapterImpl implements Adapter {

    @Override
    public Float twiceOf(Float f) {
        return null;
    }

    @Override
    public Float halfOf(Float f) {
        return null;
    }

}

AdapterImpl 클래스에서 이미 구현되어있는 Math 클래스를 사용하여 요구사항을 정의해보자. [AdapterImpl.java]

package com.bkjeon.adapter;

public class AdapterImpl implements Adapter {

    @Override
    public Float twiceOf(Float f) {
        // double -> float 를 변경하는 로직
        return (float) Math.twoTime(f.doubleValue());
    }

    @Override
    public Float halfOf(Float f) {
        // double -> float 를 변경하는 로직
        return (float) Math.half(f.doubleValue());
    }

}

잘 동작하는지 Main 클래스에서 확인해보자. [Main.java]

package com.bkjeon.adapter;

public class Main {

    public static void main(String[] args) {
        Adapter adapter = new AdapterImpl();
        System.out.println(adapter.twiceOf(100f));
        System.out.println(adapter.halfOf(88f));
    }

}

실행결과

200.0
44.0

미리 주어진 함수를 어댑터에서 바로 사용할 수 없기 때문에 요구사항에 맞춰 변경하는 로직이 필요하므로 이럴때 Adapter를 사용하면 된다.

어댑터 패턴 예시 - 2

[요구사항]

  • 알고리즘 변경을 원함
    • Math 클래스에 새롭게 두 배를 구할 수 있는 함수가 추가 되었다. -> 새로 구현된 알고리즘을 이용하도록 프로그램을 수정하자.
      package com.bkjeon.adapter;
      
      public class Math {
          // 두배
          public static double twoTime(double num) {return num * 2;}
      
          // 절반
          public static double half(double num) {return num / 2;}
      
          // 강화된 알고리즘 (추가)
          public static Double doubled(Double d) {return d * 2;}
      }
      
  • 절반을 구하는 기능에서 로그를 찍는 기능을 추가

알고리즘을 변경해보자. (Main 클래스에서 변경이 필요없이 AdapterImpl 클래스에서만 변경해줘도 구현이 가능하다.) [AdapterImpl.java]

package com.bkjeon.adapter;

public class AdapterImpl implements Adapter {

    @Override
    public Float twiceOf(Float f) {
        // return (float) Math.twoTime(f.doubleValue());
        // 알고리즘 변경
        return Math.doubled(f.doubleValue()).floatValue();
    }

    @Override
    public Float halfOf(Float f) {
        return (float) Math.half(f.doubleValue());
    }

}

절반을 구하는 기능에서 로그를 찍는 기능을 추가하자. (Main 클래스에서 변경이 필요없이 AdapterImpl 클래스에서만 변경해줘도 구현이 가능하다.) [AdapterImpl.java]

package com.bkjeon.adapter;

public class AdapterImpl implements Adapter {

    @Override
    public Float twiceOf(Float f) {
        return Math.doubled(f.doubleValue()).floatValue();
    }

    @Override
    public Float halfOf(Float f) {
        // 로그 추가
        System.out.println("절반 함수 호출 시작");
        return (float) Math.half(f.doubleValue());
    }

}

Main 클래스에서 실행하고 결과를 확인하자. [Main.java]

package com.bkjeon.adapter;

public class Main {

    public static void main(String[] args) {
        Adapter adapter = new AdapterImpl();
        System.out.println(adapter.twiceOf(100f));
        System.out.println(adapter.halfOf(88f));
        System.out.println(adapter.halfOf(88f));
        System.out.println(adapter.halfOf(88f));
        System.out.println(adapter.halfOf(88f));
        System.out.println(adapter.halfOf(88f));
    }

}

실행결과

200.0
절반 함수 호출 시작
44.0
절반 함수 호출 시작
44.0
절반 함수 호출 시작
44.0
절반 함수 호출 시작
44.0
절반 함수 호출 시작
44.0

결론적으로 요구사항은 Float으로 되는 함수를 원하지만 Math에는 주어진 알고리즘은 double이므로 바로 호출할 수 없다. 그러므로 AdapterImpl 구현체에서 알고리즘을 사용할 수 있도록 변경을 해주는 것을 알 수 있다.

 

참고: https://www.inflearn.com/course/%EC%9E%90%EB%B0%94-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4/dashboard

반응형

'Java & Kotlin > Java' 카테고리의 다른 글

[Design Pattern] Template Method Pattern  (0) 2019.12.07
[Design Pattern] Strategy Pattern  (0) 2019.12.07
[Design Pattern] Strategy Pattern  (0) 2019.10.27
iterator vs foreach  (0) 2019.08.17
JAVA 네트워크  (0) 2019.08.17
Comments