[디자인패턴] 어댑터패턴(Adapter Pattern)

고지훈·2021년 9월 10일
1

DesignPattern

목록 보기
3/16
post-thumbnail

어댑터패턴(Adapter Pattern)

어댑터패턴은 클래스의 인터페이스를 사용자가 기대하는 다른 인터페이스로 변환하는 패턴으로, 호환성이 없는 인터페이스 때문에 함께 동작할 수 없는 클래스들이 함께 작동할 수 있도록 도와준다.

어댑터패턴의 어댑터는 일반적으로 노트북 어댑터의 개념을 떠올리면 된다. 콘센트 전원에서 나오는 전기는 200V이지만, 노트북은 120V이다. 하지만 우리가 노트북을 사용할 때 아무런 불편없이 노트북 충전기를 콘센트에 꽂아 사용할 수 있다. 그 이유는 200V를 120V로 바꿔주는 어댑터가 중간에 있기 때문이다.

즉, 어댑터패턴은 노트북의 어댑터처럼 기존 클래스를 재사용할 수 있도록 중간에서 맞추어주는 역할을 수행한다.

어댑터 패턴에는 2가지 형태가 있다.
1. 클래스 어댑터 패턴(상속)
2. 인스턴스 어댑터 패턴(위임)


위 UML다이어그램은 어댑터 패턴을 나타낸 것으로, ClientTarget인터페이스를 사용하여 메서드를 호출한다. Adapter에서는 Adaptee인터페이스를 사용하여 concreateMethod호출로 변경한다. 이때, Client는 중간에 Adapter가 있다는 것을 인지하지 못한다.


어댑터패턴 구현

이번 어댑터패턴 구현 예제는 오리와 칠면조는 서로 다른 종류이기 때문에 연결될 수 없지만 어댑터패턴을 이용해 오리가 칠면조의 소리를 낼 수 있도록 구현을 했다.

// Duck.java
public interface Duck {
    public void quack();
    public void fly();
}
// MallardDuck.java
public class MallardDuck implements Duck {
    public void quack() {
        System.out.println("꽥! 꽥!");
    }

    public void fly() {
        System.out.println("먼 거리를 날아갈 수 있습니다.");
    }
}

UML다이어그램에서 Target에 해당하는 인터페이스를 정의했다. Duck은 클래스가 아닌 인터페이스이기 때문에, 상속을 받을 경우 메소드를 구현해야한다.

아래의 MallardDuck클래스에서 Duck인터페이스를 상속받고 각 메서드를 구현하였다.

// Turkey.java
public interface Turkey {
    public void gobble();
    public void fly();
}
// WildTurkey.java
public class WildTurkey implements Turkey {
    public void gobble() {
        System.out.println("고르륵! 고르륵!");
    }

    public void fly() {
        System.out.println("짧은 거리만 날아갈 수 있습니다.");
    }
}

UML다이어그램에서 Adapter가 구현하는 인터페이스이다. Client클래스는 Target인터페이스를 통해 Adaptee인 서드파티 라이브러리를 사용하게 된다.

[서드파티]

  • 프로그래밍에서 서드파티란 프로그래밍을 도와주는 plug in이나 library등을 만드는 회사를 의미한다.(개인 개발자나 팀, 혹은 업체에서 만드는 라이브러리)
  • 프로그래밍 개발과 개발자 사이에 플러그인, 라이브러리, 프레임워크를 서드파티로 볼 수 있다.
  • 제 3자로써 중간 다리 역할을 하는 것을 서드파티라고 한다.
// TurkeyAdapter.java
public class TurkeyAdapter implements Duck {
    Turkey turkey;

    public TurkeyAdapter(Turkey turkey) {
        this.turkey = turkey;
    }

    public void quack() {
        turkey.gobble();
    }

    public void fly() {
        turkey.fly();
    }
}

UML다이어그램에서 Adapter부분을 맡고 있으며, ClientAdaptee중간에 호환성이 없는 둘을 연결시켜주는 역할을 담당한다.

Target인터페이스를 구현하며, 클라이언트는 Target인터페이스를 통해 어댑터에 요청을 보낸다. Adapter는 클라이언트의 요청을 Adaptee가 이해할 수 있는 방법으로 전달하고 처리는 Adaptee에서 이루어진다.

// Client.java
public class Client {
    public static void main(String[] args) {
    	System.out.println("칠면조가 웁니다.);
        WildTurkey turkey = new WildTurkey();
        turkey.gobble();
        turkey.fly();
        
        System.out.println("칠면조 어댑터가 웁니다.);
        Duck turkeyAdpater = new TurkeyAdapter(turkey);
        turkeyAdapter.quack();
        turkeyAdapter.fly();
        
        System.out.println("오리가 웁니다.");
        MallardDuck duck = new MallardDuck();
        duck.quack();
        duck.fly();
    }
}

Client는 써드파티 라이브러리나 외부시스템을 사용하는 주체이다.

위 코드를 실행했을 때 Adapter의 경우 Duck타입으로 객체를 생성하였지만 어댑터를 통해 칠면조의 울음소리를 내고 짧은 거리를 날 수 있다.

이와 같이 서로 다른 두 가지의 인터페이스를 연결할 때, 어댑터 패턴을 사용하는 것을 확인할 수 있다.

profile
"계획에 따르기보다 변화에 대응하기를"

0개의 댓글