언어(Language)/Java

[Java] 어댑터 패턴(Adapter Pattern)이란? - 개념 및 예제

잇트루 2023. 10. 17. 23:36
반응형

어댑터 패턴(Adapter Pattern)

어댑터를 번역하면 변환기(Converter)라고 할 수 있다. 변환기의 역할은 서로 다른 두 인터페이스 사이에 통신이 가능하게 하는 것이다.

주변에서 흔히 볼 수 있는 변환기로 충전기가 있다.

C to C 케이블을 바로 콘센트에 연결할 수 없기 때문에 충전기가 케이블과 콘센트를 연결해 주는 변환기 역할을 수행한다.

 

즉, 어댑터 패턴은 애플리케이션에서 서로 호환되지 않는 인터페이스를 가진 두 개체를 함께 동작할 수 있게 만들기 위해 연결하는 디자인 패턴이다. 주로 기존의 클래스나 라이브러리를 수정하지 않고, 다른 클래스나 라이브러리와 통합하기 위해 사용된다.

 

 

어댑터 패턴 예시

어댑터 패턴이 적용되지 않은 경우

ServiceA.Java

public class ServiceA {
    void runServiceA() {
        System.out.println("ServiceA");
    }
}

 

ServiceB.Java

public class ServiceB {
    void runServiceB() {
        System.out.println("ServiceB");
    }
}

 

ClientWithNoAdapter.java

public class ClientWithNoAdapter {
    public static void main(String[] args) {
        ServiceA serviceA = new ServiceA();
        ServiceB serviceB = new ServiceB();

        serviceA.runServiceA();
        serviceB.runServiceB();
    }
}
  • 클라이언트가 ServiceA와 ServiceB를 사용하기 위해서는 각 클래스의 메서드를 직접 호출해야 한다.
  • 만약, runServiceA 메서드와 runServiceB() 메서드를 일관된 방식으로 사용하고 싶다면 어댑터 패턴을 적용할 수 있다.

 

어댑터 패턴을 적용하는 경우

  • 클라이언트는 어댑터 패턴을 사용하는 주체로 타겟(Target) 인터페이스를 통해 어댑터를 사용하여 어댑티(Adaptee) 객체의 기능을 호출할 수 있다.
  • 타겟에는 클라이언트가 사용하려는 인터페이스를 정의한다. 이를 통해 어댑터(Adapter)를 호출하여 어댑티 객체의 메서드를 실행한다.
  • 어댑터는 클라이언트와 어댑티를 연결하는 역할을 한다. 어댑터는 타겟 인터페이스를 구현하고, 구현 메서드를 호출하여 어댑티 객체의 메서드를 실행한다. 이로써 클라이언트는 어댑티 객체와 직접 상호작용하지 않고, 타겟 인터페이스를 통해 어댑티 객체의 기능을 제공할 수 있다.
  • 어댑티는 기존에 존재하는 클래스나 시스템을 나타내며, 클라이언트가 호출하기 위한 클래스 또는 인터페이스다.

 

먼저, 타겟 인터페이스를 정의한다.

public interface Target {
    void runService();
}

 

타겟 인터페이스를 구현하는 어댑터 클래스를 작성한다.

public class AdapterA implements Target {
    private ServiceA adapteeA;

    public AdapterA(ServiceA adapteeA) {
        this.adapteeA = adapteeA;
    }

    @Override
    public void runService() {
        adapteeA.runServiceA();
    }
}

public class AdapterB implements Target {
    private ServiceB adapteeB;

    public AdapterB(ServiceB adapteeB) {
        this.adapteeB = adapteeB;
    }

    @Override
    public void runService() {
        adapteeB.runServiceB();
    }
}

어댑터 A와 어댑터 B는 타겟 인터페이스를 구현하는 각각의 어댑터가 된다.

 

이제 클라이언트 코드는 어댑터 패턴을 사용하여 ServiceA와 ServiceB를 일관된 방식으로 사용할 수 있게 된다.

public class ClientWithAdapter {
    public static void main(String[] args) {
        ServiceA serviceA = new ServiceA();
        ServiceB serviceB = new ServiceB();

        Target adapterA = new AdapterA(serviceA);
        Target adapterB = new AdapterB(serviceB);

        adapterA.runService();
        adapterB.runService();
    }
}
  • 클라이언트는 어댑터를 통해 동일한 메서드인 runService()를 각각의 다른 어댑터를 통해 호출한다.

 

 

어댑터 패턴의 장단점

장점

  1. 호환성 : 서로 다른 인터페이스를 가진 두 객체를 통합할 수 있다. 기존 코드나 라이브러리를 수정하지 않고도 새로운 코드를 통합할 수 있다.
  2. 재사용성 : 기존의 클래스나 라이브러리를 활용하여 새로운 기능을 구현할 수 있게 해 준다. 기존 코드를 재사용하면서도 새로운 요구 사항을 충족시킬 수 있다.
  3. 유지보수성 : 변경된 요구 사항에 대응하기 위해 기존 코드를 수정할 필요가 없으므로 유지보수가 더 쉬워진다.
  4. 느슨한 결합 : 어댑터가 두 객체 간의 상호작용을 조정하므로 두 객체 간의 결합도가 낮아진다.

 

단점

  1. 성능 저하 : 중간에 어댑터를 추가하여 작업하기 때문에 약간의 성능 저하가 발생할 수 있다. 그러나 대부분의 상황에서 성능 저하는 미미하며, 코드의 가독성과 확장성을 개선하는 데 중점을 둬야 한다.
  2. 복잡성 : 코드가 추가되기 때문에 코드의 복잡성이 증가할 수 있다. 따라서 단순한 상황에서는 어댑터 패턴을 사용하지 않는 것이 더 나을 수 있다.
반응형