m1ndy5's coding blog

어댑터 패턴 Adapter Pattern 본문

백엔드 with java/Design Pattern

어댑터 패턴 Adapter Pattern

정민됴 2023. 12. 16. 01:41

잠깐 디자인패턴 정리를 쉬고 스프링 MVC 패턴에 대한 인강을 듣다가 어떨 때는 이걸 사용하고 어떨 때는 저걸 사용하고 싶을 때는 어댑터 패턴을 사용해야한다 라는 말이 나와서 먼저 이에 대해 정리해보려고 한다!

어댑터의 역할

예를 들어 국내에서 쓰던 충전기를 일본에가서 사용하려고 하면 당연히 호환이 안될 것이다.
이때 어댑터를 사용하여 맞춰준 경험이 있을 것이다!
어댑터는 특정 인터페이스를 클라이언트에서 요구하는 형태로 적응시키는 역할을 한다.

객체지향 어댑터

어떤 소프트웨어 시스템에 새로운 업체에서 제공한 클래스 라이브러리를 사용해야 하는데 그 업체에서 사용하는 인터페이스가 기존에 사용하던 인터페이스와 다르다고 가정해 보자
그렇지만 기존 코드를 바꿔서 이 문제를 해결하기엔 일이 너무 복잡해지기 때문에 기존 시스템과 업체에서 제공한 클래스 사이에 어댑터를 끼워주면 된다.
어댑터는 클라이언트로부터 요청을 받아 새로운 업체에서 제공하는 클래스를 클라이언트가 받아들일 수 있는 형태의 요청으로 변환해 주는 중개인 역할을 한다.

어댑터 사용 방법

Duck interface

public interface Duck{
    public void quack();
    public void fly();
}

Duck을 구현하는 MallardDuck Class

public class MallardDuck implements Duck{
    public void quack(){
        System.out.println("꽥");
    }

    public void fly(){
        System.out.println("날고 있어요!!");
    }
}

이번엔 새로운 Turkey라는 인터페이스가 나타났다고 해보자

Turkey interface

public interface Turkey{
    public void gobble(); // 칠면조는 꽥꽥하지 않고 골골(?)거린다.
    public void fly();
}

Turkey를 구현하는 WildTurkey Class

public class WildTurkey implements Turkey{
    public void gobble(){
        System.out.println("골골");
    }

    public void fly(){
        System.out.println("짧은 거리를 날고 있어요!");
    }
}

Turkey를 Duck과 맞춰보자

Duck을 구현하는 TurkeyAdapter

public class TurkeyAdapter implements Duck{
    Turkey turkey;

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

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

    public void fly(){
        for(int i = 0; i < 5; i++){
            turkey.fly();
         }
    }
}

적용 예시

public class DuckTestDrive{
    public static void main(String[] args){
        Duck duck = new MallardDuck();

        Turkey turkey = new WildTurkey();
        Duck turkeyAdapter = new TurkeyAdapter(turkey);

        System.out.println("칠면조가 말하길");
        turkey.gobble();
        turkey.fly();

        System.out.println("\n오리가 말하길");
        testDuck(duck);

        System.out.println("\n칠면조 어댑터가 말하길");
        testDuck(turkeyAdapter);
    }

    static void testDuck(Duck duck){
        duck.quack();
        duck.fly();
    }
}

결과
칠면조가 말하길
골골
짧은 거리를 날고 있어요!
\n
오리가 말하길

날고 있어요!
\n
칠면조 어댑터가 말하길
골골
짧은 거리를 날고 있어요!


이렇게 Duck의 함수를 사용했지만 결과는 Turkey의 함수가 잘 동작하는 것을 볼 수 있다.
이 패턴을 사용하면 호횐되지 않는 인터페이스를 사용하는 클라이언트를 그대로 활용할 수 있다.
이렇게 했을 때 장점은 변경 내역이 어댑터에 캡슐화되기 때문에 나중에 인터페이스가 바뀌더라도 클라이언트를 바꿀 필요가 없다.
어댑터를 새로 바뀐 인터페이스로 감쌀 때는 객체 구성을 사용한다.(TurkeyAdapter에 Turkey turkey; 부분 -> 얘를 바꿔서 사용하면 됨)