개요

나는 지금까지 디자인 패턴에 대해서 잘 안다고 생각하고 있었는데, 이번 대학교 시험을 보는 친구에게 디자인 패턴에 관련된 질문을 받았을 때 막상 잘 대답하지 못했다. 그래서 이번에 확실히 디자인 패턴에 대한 개념을 깨우치기 위해서 자주 사용되는 GOF 패턴에 대해서 작성하기로 했다.

알아야 할 점

디자인 패턴은 만능이 아니다!

패턴쟁이가 되지 말자.

어댑터 패턴(Adapter Pattern)

어댑터 패턴은 호환되지 않는 인터페이스를 가진 객체들이 서로 연결될 수 있도록 하는 구조적 디자인 패턴이다.

다들 예시를 들어서 설명을 할 때 많이들 전기 코드를 들어 설명한다. 만약 내가 일본이나 미국으로 여행을 가려고 할 때, 한국에 사는 내 입장에서는 당연히 기존 220v 전기 코드를 그 나라의 맞는 110v 콘센트에 꽂기 위해서 변환 어댑터를 준비해야 할 것이다. 이때 이러한 일련의 과정은 상단의 정의에서 설명한 어댑터 패턴과 동일한 흐름을 가진다. 220v(레거시 클래스)코드를 변압기(어댑터)에 꽂고 해당 변압기를 110v콘센트(호환되지 않는 클래스 또는 인터페이스)에 꽂아 원활히 동작하도록 하는 것이다.

한 번 코드를 통해서 살펴보자.

// 자바 코드
// 110V 소켓 인터페이스
interface Socket110V {
    void providePower110V();
}

// 220V 플러그 클래스
class Plug220V {
    void connect220V() {
        System.out.println("220V 전원에 연결되었습니다.");
    }
}

// 어댑터 클래스
class Adapter220Vto110V implements Socket110V {
    private Plug220V plug220V;

    Adapter220Vto110V(Plug220V plug220V) {
        this.plug220V = plug220V;
    }

    @Override
    public void providePower110V() {
        convert220Vto110V();
        plug220V.connect220V();
    }

    private void convert220Vto110V() {
        System.out.println("220V 전원을 110V 전원으로 변환합니다.");
    }
}

// 클라이언트 코드
public class Client {
    public static void main(String[] args) {
        Plug220V plug220V = new Plug220V();
        Socket110V socket110V = new Adapter220Vto110V(plug220V);
        socket110V.providePower110V();
    }
}

여기서 실제 클라이언트 클래스(실제로 110v와 220v를 사용하는 곳)에서는 기존 220v 클래스 객체를 그대로 선언한 채로 어댑터 클래스를 추가적으로 도입하여 사용하고 싶은 110v와 연결되는 것을 알 수 있다.

이를 통해 기존의 220v 클래스 코드를 변경하지 않고 어댑터를 도입하여 코드를 전환할 110v에 맞춰서 변환하고 그렇게 변환된 값을 활용하여 110v 클래스에 접근 가능하도록 함을 할 수 있다.

이렇듯 어댑터 패턴을 활용하면 기존 클래스의 코드를 변형하지 않고 어댑터를 통한 추가적인 기능 확장이 가능하다.

어댑터 패턴의 구현 방식은 객체 어댑터와 클래스 어댑터로 나뉜다.(상기 코드에서 사용한 방식은 객체 어댑터 방식이다.)

객체 어댑터 방식

스크린샷 2024-06-17 오전 1.46.41.png

객체 어댑터 방식은 객체 합성 원칙(쉽게 말해서 사용해야 하는 클래스를 멤버 변수로 추가)을 사용한다. 객체 어댑터 방식은 기존의 사용한 객체(220v 클래스)를 래핑(멤버 변수로 추가한다.)하고 거기에 추가적으로 확장하고 싶은 서비스(110v 클래스)의 인터페이스를 구현함으로써 이루어진다.