Back-End/Java & Spring
Adapter 패턴 : 호환되지 않는 인터페이스를 연결하는 설계 전략
봉의일상
2025. 5. 11. 22:23
1. Adapter 패턴이란?
Adapter 패턴은 서로 호환되지 않는 두 객체를 연결해주는 중간 매개체 역할을 하는 구조 패턴입니다. 즉, 기존 인터페이스를 클라이언트가 기대하는 인터페이스로 변환하여, 기존 코드의 변경 없이도 새로운 기능을 통합할 수 있게 해줍니다.
사용 목적
- 기존 코드를 수정하지 않고 외부 시스템 또는 레거시 코드를 통합
- 인터페이스가 맞지 않아 함께 사용하기 어려운 두 객체를 연결
- 시스템 확장성 및 유지보수성 향상
2. 구조와 동작 원리
기본 구조
클라이언트 → Target 인터페이스
↑
Adapter ← Adaptee (호환되지 않는 기존 객체)
- Target: 클라이언트가 기대하는 인터페이스
- Adaptee: 기존 또는 외부 시스템의 실제 기능을 가진 객체
- Adapter: Adaptee의 기능을 감싸서 Target처럼 보이게 해주는 클래스
3. 예시 코드 (Java 스타일)
// 클라이언트가 기대하는 인터페이스
public interface MediaPlayer {
void play(String filename);
}
// 기존 시스템 또는 외부 API
public class LegacyAudioPlayer {
public void playFile(String path) {
System.out.println("재생 중: " + path);
}
}
// Adapter
public class AudioPlayerAdapter implements MediaPlayer {
private final LegacyAudioPlayer legacyPlayer = new LegacyAudioPlayer();
public void play(String filename) {
legacyPlayer.playFile(filename);
}
}
4. 어떤 문제를 해결하기 위해 자주 쓰일까?
- 외부 라이브러리의 인터페이스가 우리가 쓰는 방식과 다를 때
- 기존 시스템(레거시 코드)을 리팩터링 없이 유지하면서 새 코드와 연결할 때
- 다양한 데이터 포맷(JSON, XML 등)을 표준 인터페이스로 맞춰야 할 때
5. 실무 적용 예시
1) 외부 결제 API 연동
- 카드사마다 결제 API 구조가 다를 경우, 내부에서 사용하는 공통 인터페이스(PaymentGateway)를 만들고, 각 카드사마다 Adapter를 구현하여 연결
2) Spring에서 HandlerAdapter
- 다양한 타입의 Controller를 일관된 방식으로 처리하기 위해, Spring MVC는 HandlerAdapter를 통해 DispatcherServlet과 실제 Controller를 연결
3) 파일 포맷 변환기
- 예: CSV, Excel, JSON 데이터를 내부 표준 객체로 변환하는 Adapter 구성
5.5. Adapter 패턴과 API Gateway의 관계
API Gateway는 여러 마이크로서비스의 진입점을 통합하여 클라이언트와 서버 간의 요청을 중재하는 역할을 합니다.
이 구조는 Adapter 패턴과 매우 유사한 목적을 가지고 있습니다.
Adapter 패턴 | API Gateway | |
역할 | 코드 단위의 인터페이스 변환 | 네트워크 레벨의 요청 라우팅 및 변환 |
목적 | 서로 다른 시스템 간 호환성 확보 | 여러 API를 통합된 진입점으로 제공 |
범위 | 클래스/객체 설계 패턴 | 시스템/아키텍처 계층 구성 요소 |
예를 들어, 클라이언트가 /pay로 요청을 보냈을 때 API Gateway가 내부적으로 /kakao, /naverpay 등의 실제 서비스로 요청을 라우팅해주는 방식은, 내부의 다양한 서비스 구조를 클라이언트에 맞춰 추상화해준다는 점에서 Adapter와 동일한 설계 철학을 따릅니다. 따라서 API Gateway는 실질적으로 Adapter 패턴을 아키텍처 레벨에서 구현한 사례라고 볼 수 있습니다.
장점 | 단점 |
기존 코드 변경 없이 시스템 통합 가능 | Adapter 클래스가 많아질 수 있음 |
레거시 코드 재사용 가능 | 설계가 복잡해질 수 있음 |
인터페이스 호환성 확보 | 성능 이슈 발생 가능성 (간접 호출 등) |