7. Adapter Pattern

2021. 10. 14. 17:25Computer Sciences/Design Patterns

문제

어댑터는 우리 주위에서 흔하게 볼수 있는 것이다. 110V를 220V로 변환해야 하는 경우가 대표적이다. 우리나라는 220V를 쓰는데 유럽 같은 경우 110V를 쓴다. 그래서 우리가 만약 외국 여행을 가는데 충전기를 사용하려면 어댑터를 갖고 가서 110V를 220V로 바꿔줘야 한다. 프로그래밍에서도 이런 경우가 발생한다. 우리가 운영하던 시스템이 있는데 외부 업체에서 인터페이스를 제공해주었다. 그런데 우리 시스템과 연결이 되지 않는 경우 어떻게 해야 할까? 여기서 어댑터를 사용할 수 있다.

오리와 칠면조

우리는 오리와 칠면조 객체를 가지고 있다.

public class MallardDuck implements Duck {

    @Override
    public void quack() {
        System.out.println("Quack");
    }

    @Override
    public void fly() {
        System.out.println("I'm flying");
    }
}
public class WildTurkey implements Turkey {

    @Override
    public void gobble() {
        System.out.println("Gobble gobble");
    }

    @Override
    public void fly() {
        System.out.println("I'm flying a short distance");
    }
}

각각은 Duck 인터페이스와 Turkey 인터페이스를 구현한다.

public interface Duck {

    void quack();

    void fly();
}
public interface Turkey {

    void gobble();

    void fly();
}

그런데 어느날 요청사항이 들어왔다. 겉모습은 오리인데 동작은 칠면조처럼 해달라는 것이다. 이런 경우 어댑터 패턴을 적용할 수 있다.

public class TurkeyAdapter implements Duck {

    Turkey turkey;

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

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

    @Override
    public void fly() {
        // 두 번 날개짓한다.
        turkey.fly();
        turkey.fly();
    }
}
public class DuckTest {

    public static void main(String[] args) {

        MallardDuck duck = new MallardDuck();
        WildTurkey turkey = new WildTurkey();
        Duck turkeyAdapter = new TurkeyAdapter(turkey);

        System.out.println("Turkey says...");
        turkey.gobble();
        turkey.fly();

        System.out.println("\nDuck says...");
        duck.quack();
        duck.fly();

        System.out.println("\nThe TurkeyAdapter says...");
        turkeyAdapter.quack();
        turkeyAdapter.fly();
    }
}

어댑터 패턴

한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환하는 패턴이다. 어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다. 클라이언트에서 이를 사용하는 방법은 간단하다. 사용하고자 하는 타겟의 인터페이스를 구현하는데 연결하고자 하는 인터페이스의 구현 클래스를 멤버 변수로 가지게 한 다음에 타겟 인터페이스의 동작을 실행할 때 멤버 변수의 메서드를 동작시키면 된다. 말로 풀어쓰면 조금 복잡한 거 같은데 위에서 작성한 DuckTurkey, TurkeyAdapter의 관계를 조금만 보면 이해할 수 있다. 이를 클래스 다이어그램으로 나타내면 다음과 같다.

어댑터 패턴에는 여러 객체지향 원칙이 반영되어 있다. 어댑티를 새로 바뀐 인터페이스에서 사용할 땐 객체 컴포지션을 사용한다. 이런 접근법을 사용하면 어댑티의 어떤 서브 클래스에 대해서도 어댑터를 쓸 수 있다는 장점이 있다.

그리고 클라이언트는 구현 클래스가 아닌 인터페이스와 연관된다. 각각 서로 다른 클래스들로 변환시키는 여러 어댑터를 사용할 수도 있다는 말이다. 이로써 인터페이스만 지킨다면 나중에 어떤 다른 구현체들을 추가하는 것도 가능해진다.

'Computer Sciences > Design Patterns' 카테고리의 다른 글

9. Template Method Pattern  (0) 2021.10.14
8. Facade Pattern  (0) 2021.10.14
6. Command Pattern  (0) 2021.10.14
5. Singleton Pattern  (0) 2021.09.15
4. Abstract Factory Method  (0) 2021.09.15