본문 바로가기

Develop/Design Pattern

[Design Pattern] 어댑터 (Adaptor) 패턴

728x90

1. 개요

  • 어댑터 디자인 패턴 (Adaptor Design Pattern)은 서로 다른 인터페이스를 implements 하는 클래스를 함께 동작하도록 하는 패턴이다.

2. 상황

  • 서로 다른 두 인터페이스가 유사한 method 를 가질 때
  • 기존 인터페이스를 변경할 수 없을 때

3. 다이어그램

adaptor-default

3.1. 설명

  • TargetAdaptor가 유사한 method 를 가지고 있고,
  • Adaptee를 수정하기 힘든 상황이라면

Adaptor 디자인 패턴을 사용할 수 있다.

4. 구현

interface Target { void method(); }

interface Adaptee { void similarMethod(); }

class Adaptor implements Target {
  private final Adaptee adaptee;

  public Adaptor(Adaptee adaptee) {
    this.adaptee = adaptee;
  }

  @Override
  void method() { adaptee.similarMethod(); }
}

class AdapteeImpl implements Adaptee {
  @Override
  void similarMethod() {}
}
class Client {
  public static void main(String[] args) {
    Adaptee adaptee = new AdapteeImpl();
    Target target = new Adapter(adaptee);
    target.method(); 
  }
}

위에서는 target.method() 가 결국 adaptee.similarMethod() 를 수행한다.

그렇다면 왜 굳이 AdapteeTarget 의 형태로 바꾸는 것일까?


예제를 통해 살펴보자.

5. 예시

  • TossPay 를 KakaoPay 와 같이 처리하는 예시 코드이다.
public interface KakaoPay {
  String getCustomer();
  int getAmount();
  void checkout(int cost);
}

public class KakaoPayImpl implements KakaoPay {
  private String customer;
  private int amount;

  public KakaoPayImpl(String name) {
    customer = name; amount = 1000;
  }

  @Override
  public String getCustomer() { return customer; }
  @Override
  public int getAmount() { return amount; }
  @Override
  public void checkout(int cost) { amount -= cost; }
}
  • KakaoPaygetCustomer(), getAmount(), checkout() 의 세 method 를 가지고 있다.
public interface TossPay {
  String getUser();
  int getMoney();
  void pay(int cost);
}

public class TossPayImpl implements TossPay {
  private String user;
  private int money;

  public TossPayImpl(String name) {
    user = name; money = 1000;
  }

  @Override
  public String getUser() { return user; }
  @Override
  public int getMoney() { return money; }
  @Override
  public void pay(int cost) { money -= cost; }
}
  • TossPaygetUser(), getMoney(), pay() 의 세 method 를 가지고 있다.

KakaoPayTossPay 에는 비슷한 동작을 수행하는 method 가 각각 다르게 구현되어 있다.

이때, TossPay 의 동작을 KakaoPay 에서 구현된 method 호출을 통해 실행하고자 한다면 Adaptor 패턴을 사용할 수 있다.

public class TossToKakaoPayAdaptor implements KakaoPay {
  private final TossPay tossPay;

  public TossToKakaoPayAdaptor(TossPay pay) { tossPay = pay; }

  @Override
  public String getCustomer() { return tossPay.getUser(); }
  @Override
  public int getAmount() { return tossPay.getMoney(); }
  @Override
  public void checkout(int cost) { tossPay.pay(cost); }
}
public class Client {
  public static void main(String[] args) {
    List<KakaoPay> cards = new ArrayList<>();

    cards.add(new KakaoPayImpl("Jane"));
    cards.add(new KakaoPayImpl("James"));
    cards.add(new TossToKakaoPayAdaptor(new TossPayImpl("John")));

    for (KakaoPay card : cards) {
      card.checkout(500);
      System.out.println(card.getCustomer() + ": " + card.getAmount());
    }
  }
}

ClientAdaptor 를 통해 TossPayKakaoPay 같이 사용할 수 있다.


실행결과

Jane: 500
James: 500
John: 1500

6. 장단점

6.1. 장점

  • SRP, OCP 원칙을 만족한다.
  • 디버깅이 비교적 쉽다.

6.2. 단점

  • 코드 복잡성이 증가한다.

관련 포스팅

참고 자료

728x90