구조 패턴 중 하나인 어댑터 패턴은 특정 인터페이스를 다른 형식으로 변환하여 호환되지 않는 클래스 간의 통합을 가능하게 합니다. 이 패턴은 기존 시스템과 새로운 요구사항 간의 인터페이스 호환성을 유지하기 위해 설계 단계에서 고려되지 않으며, 이미 구현된 시스템에 대한 보완적 접근입니다.
주요 구성 요소는 다음과 같습니다:
- 목적 인터페이스(Target): 사용자가 기대하는 인터페이스로, 추상클래스나 인터페이스 형태로 정의됩니다.
- 원본 인터페이스(Adaptee): 변환 대상이 되는 기존 클래스
- 어댑터(Adapter): 원본 인터페이스를 감싸서 목적 인터페이스로 변환하는 중간 레이어
예시 시나리오: 기존 제품의 기능 확장으로 인해 새로운 인터페이스가 추가되지만, 기존 인터페이스와 기능이 유사한 경우. 기존 코드를 수정하지 않고 새로운 인터페이스 내부에서 기존 로직을 호출하는 방식으로 구현할 수 있습니다.
두 가지 주요 구현 방식 중 추천되는 방식은 객체 조합 방식입니다:
- 클래스 기반 어댑터: 상속을 통해 구현
- 객체 기반 어댑터: 참조를 통해 구현
아래는 객체 기반 어댑터를 사용한 예제입니다. 대한민국 전원 커넥터를 홍콩형으로 변환하는 시나리오를 가정합니다.
원본 인터페이스 정의:
package com.design.mode.adapter.example01;
/**
* @Author: 倚天照海
* @Description: 원본 인터페이스 역할
*/
public class KoreaSocket {
public void providePower(){
System.out.println("대한민국 표준 콘센트를 통해 전원 공급");
}
}
목표 인터페이스 정의:
package com.design.mode.adapter.example01;
/**
* @Author: 倚天照海
* @Description: 목적 인터페이스 역할
*/
public interface HKSocket {
/**
* 홍콩형 콘센트를 통해 전원 공급
*/
void providePower();
}
어댑터 구현:
package com.design.mode.adapter.example01;
/**
* @Author: 倚天照海
* @Description: 어댑터 역할
*/
public class SocketConverter implements HKSocket {
private KoreaSocket socket;
public SocketConverter() {
}
public SocketConverter(KoreaSocket socket) {
this.socket = socket;
}
@Override
public void providePower() {
System.out.println("대한민국 콘센트를 홍콩형으로 변환하여 전원 공급");
socket.providePower();
}
}
사용자 역할 구현:
package com.design.mode.adapter.example01;
public class HKCharger {
/**
* 홍콩형 충전기, 휴대폰이나 노트북 충전
*/
public void charge(HKSocket socket) {
System.out.println("홍콩형 충전기를 사용하여 휴대폰 충전");
socket.providePower();
}
}
테스트 코드:
package com.design.mode.adapter.example01;
public class AdapterExample01 {
public static void main(String[] args) {
KoreaSocket socket = new KoreaSocket();
Adapter converter = new Adapter(socket);
converter.charge();
}
}