어댑터란 무엇일까요 ?
어댑터를 한글로 번역하면 변환기(converter)라고 할 수 있습니다.
변환기의 역할은 서로 다른 두 인터페이스 사이에 통신을 가능하게 하는 것 입니다.
여러분은 이미 어댑터를 일상에 적용하고 있었을지도 모릅니다..
대표적인 예로 충전기가 있습니다. 휴대폰을 콘센트에 바로 연결할 수 없기 때문에 충전기라는 변환기를 이용하여 휴대폰을 충전할 수 있습니다.
자바에서의 대표적인 예는 JDBC(Java Database Connectivity)가 있습니다.
JDBC는 여러 데이터베이스(MySQL, Oracle, h2, Postgresql ..)를 단일한 인터페이스로 조작이 가능하도록 도와주는 변환기입니다.
즉 어댑터 패턴은 SOLID에서 개방 폐쇄 원칙(OCP)을 활용한 설계 패턴이라고 할 수 있습니다.
OCP : 객체의 확장은 개방적이고, 객체의 수정은 폐쇄적으로 설계하는 원칙
어댑터는 크게 2가지로 나눠집니다.
Adaptee 를 상속하여 호환되게 하려는 메소드 사용
구현체를 넘겨받아 호환되게 하려는 메소드 사용
어댑터 패턴을 코드로 알아보겠습니다.
아래의 두 코드는 비슷한 기능을 가진 클래스들입니다.
package adapter;
public class ServiceA {
public void runServiceA(){
System.out.println("ServiceA");
}
}
package adapter;
public class ServiceB {
public void runServiceB(){
System.out.println("ServiceB");
}
}
ServiceA와 ServiceB의 참조변수를 각각 생성해서 메서드를 호출해줍니다.
package adapter;
public class ClientWithNoAdapter {
public static void main(String[] args) {
ServiceA sa = new ServiceA();
ServiceB sb = new ServiceB();
sa.runServiceA();
sb.runServiceB();
}
}
하지만 이렇게 설계를 하면 각 메서드가 비슷한 일을 하지만 호출하는 메서드명이 다른 것을 볼 수 있습니다.
이 글에서는 오브젝트 어댑터를 사용해보도록 하겠습니다.
그럼 어댑터 패턴을 적용해서 위의 코드를 리팩토링 해보겠습니다. 위의 ServiceA와 ServiceB는 그대로 사용하겠습니다.
package adapter.adapter;
import adapter.noAdapter.ServiceA;
public class AdapterServiceA {
ServiceA sa1 = new ServiceA();
void runService(){
sa1.runServiceA();
}
}
package adapter.adapter;
import adapter.noAdapter.ServiceB;
public class AdapterServiceB {
ServiceB sb1 = new ServiceB();
void runService(){
sb1.runServiceB();
}
}
package adapter.adapter;
public class ClientWithAdapter {
public static void main(String[] args) {
AdapterServiceA sa = new AdapterServiceA();
AdapterServiceB sb = new AdapterServiceB();
sa.runService();
sb.runService();
}
}
이렇게 중간에 Adapter 클래스를 생성해줌으로써
메서드를 호출당하는 쪽의 메서드를 호출하는 쪽의 코드에 대응하도록 중간에 변환기를 통해 호출하게 되는 패턴입니다.