Java/디자인패턴

Design Pattern - Adapter Pattern

728x90

본 포스팅의 내용은 아래의 인프런 강의를 참조하여 작성되었습니다.

(www.inflearn.com/course/%EC%9E%90%EB%B0%94-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4/dashboard)

 

 

 

 

- Adapter Pattern

: 어댑터 라는 것은, 사전적 으로는 "기계나 기계 따위를 다목적 으로 사용 하기 위한 보조 기구 또는 그것을 부착 하기 위한 보조 기구" 로 해석 된다 

 

일상 생활 에서, 해외여행시에 챙겨가는 볼트 변환기 같은 것을 어댑터라고 표현하기도 한다. 

 

즉, 어댑터라는것은 호환이 되지 않는 무언가를 호환이 되게 만들어주는 보조장치라고 볼 수 있다. 

 

디자인 패턴에서의 어댑터 패턴도 어떤 클래스 에서 제공하지 않는 (사용자가 원하는) 기능을 인터페이스로 만들어서 호환성을 제공하는 것을 말한다.

 

 

- 상속 그리고 합성

어댑터 패턴을 이해하기 이전에, 필요한 사전지식으로 자바에서의 상속과 합성에 대해서 알고 있어야 이해할 수 있다.

자세한 사항은 아래 참조

www.darkkaiser.com/2007/07/16/%EC%83%81%EC%86%8D%EA%B3%BC-%ED%95%A9%EC%84%B1/

 

상속과 합성 – DarkKaiser의 블로그

‘Gof의 디자인 패턴’에서는 “Favor object composition over class inheritance”라고 말한다. 이를 해석하면 “객체 합성이 클래스 상속보다 더 나은 방법이다”라는 의미이다. 객체지향 시스템에서 기능

www.darkkaiser.com

 

- 코드 예제

어댑터 패턴에 대한 코드 예제를 알아보자

 

정의에서 언급한것처럼 어떤 볼트 변환기 개념을 기반으로하는 어떤 코드가 있다고 가정해보자

 

- Volt.java

public class Volt {
    private int volts;
 
    public Volt(int volts) {
        this.volts = volts;
    }
 
    public int getVolts() {
        return volts;
    }
 
    public void setVolts(int volts) {
        this.volts = volts;
    }
}
cs

-> Volt 클래스는 단순히 volts 라는 멤버변수를 갖는 POJO 이다.

 

 

- Socket.java

public class Socket {
    public Volt getVolt() {
        return new Volt(120);
    }
}
cs

-> Socket 클래스는 120 볼트만 제공하는 클래스여서, 다른 볼트로 호환되려면 볼트 변환기가 필요하다

 

 

- SocketAdapter.java

public interface SocketAdapter {
    Volt get120Volt();
    Volt get12Volt();
    Volt get3Volt();
}
cs

-> 볼트 변환기 역할을 하는 인터페이스이다.

 

 

어댑터 패턴을 구현하는 방식은 Class Adapter (Inheritance, 상속) 방식과 Object Adapter (Composition, 합성) 방식 이렇게 두가지로 나뉜다.

 

 

1. Class Adapter 

 

- SocketClassAdapterImpl.java

// Class Adapter (Inheritance)
public class SocketClassAdapterImpl extends Socket implements SocketAdapter {
 
    private Volt convertVolt(Volt v, int i) {
        return new Volt(v.getVolts() / i);
    }
 
    @Override
    public Volt get120Volt() {
        return getVolt();
    }
 
    @Override
    public Volt get12Volt() {
        Volt v = getVolt();
        return convertVolt(v, 10);
    }
 
    @Override
    public Volt get3Volt() {
        Volt v = getVolt();
        return convertVolt(v, 40);
    }
}
cs

 

2. Object Adapter 

// Object Adapter (Composition)
public class SocketObjectAdapterImpl implements SocketAdapter{
 
    // Composition for adapter pattern
    private Socket socket = new Socket();
 
    private Volt convertVolt(Volt v, int i) {
        return new Volt(v.getVolts() / i);
    }
 
    @Override
    public Volt get120Volt() {
        return socket.getVolt();
    }
 
    @Override
    public Volt get12Volt() {
        Volt v = socket.getVolt();
        return convertVolt(v, 10);
    }
 
    @Override
    public Volt get3Volt() {
        Volt v = socket.getVolt();
        return convertVolt(v, 40);
    }
}
cs

 

-> 첫번째 방식은, Socket 클래스를 상속 받아서, 어댑터 역할을 하는 인터페이스에 정의된 함수들에 대해서 오버라이드를 수행하지만, 두번째 방식은, 상속이 아닌 합성 방식으로 필드 변수 Socket 을 선언하고, 이를 기반으로 오버라이드를 수행하는것을 볼 수 있다.

 

위 예제에 대한 다이어그램을 나타내면 아래와 같다

 

 

 

Volt 클래스가 기본적으로 갖고 있는 120 볼트 외에도 다른 볼트 값을 쓰기 위해서 SocketAdapter 라는 인터페이스를 사용했고 이를 구현하는 두개의 클래스 SocketClassAdapterImpl 와 SocketObjectAdapterImpl 중 둘 중 하나를 선택해서 볼트값을 전환해주면 된다

 

- Main.java

public class Main {
    
    public static void main(String[] args) {
        testClassAdapter();
        testObjectAdapter();
    }
 
    private static void testObjectAdapter() {
        SocketAdapter socketAdapter = new SocketObjectAdapterImpl();
        Volt v3 = getVolt(socketAdapter, 3);
        Volt v12 = getVolt(socketAdapter, 12);
        Volt v120 = getVolt(socketAdapter, 120);
 
        System.out.println("v3 volts using object adapter = " + v3.getVolts());
        System.out.println("v12 volts using object adapter = " + v12.getVolts());
        System.out.println("v120 volts using object adapter = " + v120.getVolts());
    }
 
    private static void testClassAdapter() {
        SocketAdapter socketAdapter = new SocketClassAdapterImpl();
        Volt v3 = getVolt(socketAdapter, 3);
        Volt v12 = getVolt(socketAdapter, 12);
        Volt v120 = getVolt(socketAdapter, 120);
 
        System.out.println("v3 volts using class adapter = " + v3.getVolts());
        System.out.println("v12 volts using class adapter = " + v12.getVolts());
        System.out.println("v120 volts using class adapter = " + v120.getVolts());
    }
 
    private static Volt getVolt(SocketAdapter socketAdapter, int i) {
        switch (i) {
            case 3return socketAdapter.get3Volt();
            case 12return socketAdapter.get12Volt();
            case 120return socketAdapter.get120Volt();
        }
        return socketAdapter.get120Volt();
    }
}
cs

 

 

참조한 블로그 : readystory.tistory.com/125

 

[구조 패턴] 어댑터 패턴(Adapter Pattern) 이해 및 예제

어댑터 패턴은 구조 패턴(Structural Pattern) 중 하나로, 서로 관계없는 인터페이스들을 함께 사용할 수 있게 하는 패턴입니다. 구조 패턴(Structural Pattern)이란? 구조 패턴이란 작은 클래스들을 상속과

readystory.tistory.com

 

전체 코드 : github.com/khusw/Design-Pattern/tree/master/Adapter-Pattern

728x90

'Java > 디자인패턴' 카테고리의 다른 글

Design Pattern - Strategy Pattern  (0) 2021.02.23
Design Pattern - Overview  (0) 2021.02.23