1. 어댑터 패턴 (Adapter Pattern)
1️⃣ 어댑터 패턴이란?
1) 정의
호환되지 않는 인터페이스를 연결해주는 변환 패턴
서로 다른 형식의 코드를 직접 수정하지 않고 중간 변환 객체(어댑터)를 통해 연결
2) 핵심 개념
✔ 인터페이스 불일치 해결
✔ 기존 코드 수정 최소화
✔ 중간 변환 계층 추가
Client → Adapter → Adaptee2️⃣ 비유로 이해하기
1) 🔌 콘센트 어댑터
- 플러그 모양 불일치 해결
- 규격 변환
- 기존 기기 변경 불필요
➡️ 소프트웨어 구조와 동일
2) 🌍 통역사
- 서로 다른 언어 변환
- 직접 대화 불가능 문제 해결
3️⃣ 어댑터가 필요한 이유
1) 문제 상황
- 이미 존재하는 코드(기존 시스템)와 새로운 코드(라이브러리/API)의 인터페이스가 다름
- 예
기존 시스템 → playSound()
새 라이브러리 → startAudio()➡️ 직접 호출 불가능 ❌
2) 해결 방식
- 어댑터 추가
playSound() → Adapter → startAudio()4️⃣ 사용 목적
- 기존 코드 보호
- 인터페이스 불일치 해결
- 외부 시스템 연동 용이
- 결합도 감소
5️⃣ 어댑터 패턴의 장단점
1) 장점 👍
- 기존 코드 수정 최소화
- 재사용성 증가
- 확장 용이
- 유지보수 편리
2) 단점 👎
- 클래스/객체 증가
- 구조가 복잡해질 수 있음
6️⃣ 사용 시점 (언제 쓰는가?)
- 외부 API 연동
- 레거시 시스템 유지
- 라이브러리 교체
- 인터페이스 변환 필요 시
7️⃣ 어댑터 패턴의 구조
1) Client
- 사용 주체 (우리 코드)
2) Target
- Client가 기대하는 인터페이스
3) Adapter
- 인터페이스 변환 담당
4) Adaptee
- 실제 기능 제공 객체 (외부 코드)
8️⃣ 간단 예시
1) 기존 시스템
playSound()
2) 새 라이브러리
startAudio()
3) 어댑터
playSound() { startAudio() 호출 }
➡️ Client는 기존 방식 그대로 사용 가능
2. 실습 (ex03)
1️⃣ 라이브러리가 인터페이스와 맞지 않을 때 변환해서 연결
1) OuterRabbit.java (library - 이미 만들어진 도구)
C:\workspace\java_lab\designapp\src\ex03\lib\OuterRabbit.java
package ex03.lib;
// .class로 컴파일된 것
public class OuterRabbit {
private String fullname = "토끼";
public String getFullname() {
return fullname;
}
}2) App.java
C:\workspace\java_lab\designapp\src\ex03\App.java
package ex03;
import ex03.lib.OuterRabbit;
// 어댑터 패턴 : 인터페이스에 맞게 변환해주는 역할
// 용도 1 : 이미 만들어진 도구가 인터페이스와 맞지 않을 때 변환해서 연결
// 용도 2 : 아직 만들지 않은 도구를 미리 연결 (인터페이스가 없다면)
public class App {
public static void main(String[] args) {
Tiger tiger = new Tiger();
Mouse mouse = new Mouse();
OuterRabbit rabbit = new OuterRabbit();
Doorman doorman = new Doorman();
doorman.쫓아내(rabbit);
}
}3) RabbitAdapter.java
C:\workspace\java_lab\designapp\src\ex03\RabbitAdapter.java
package ex03;
public class RabbitAdapter extends Animal {
@Override
public String getName() {
return "토끼";
}
}4) App.java
C:\workspace\java_lab\designapp\src\ex03\App.java
package ex03;
import ex03.lib.OuterRabbit;
// 어댑터 패턴 : 인터페이스에 맞게 변환해주는 역할
// 용도 1 : 이미 만들어진 도구가 인터페이스와 맞지 않을 때 변환해서 연결
// 용도 2 : 아직 만들지 않은 도구를 미리 연결 (인터페이스가 없다면)
public class App {
public static void main(String[] args) {
Tiger tiger = new Tiger();
Mouse mouse = new Mouse();
RabbitAdapter rabbit = new RabbitAdapter();
Doorman doorman = new Doorman();
doorman.쫓아내(rabbit);
}
}5) 결과

6) RabbitAdapter.java
package ex03;
import ex03.lib.OuterRabbit;
public class RabbitAdapter extends Animal {
private OuterRabbit outerRabbit;
public RabbitAdapter(OuterRabbit outerRabbit) {
this.outerRabbit = outerRabbit;
}
@Override
public String getName() {
return outerRabbit.getFullname();
}
}7) App.java
package ex03;
import ex03.lib.OuterRabbit;
// 어댑터 패턴 : 인터페이스에 맞게 변환해주는 역할
// 용도 1 : 이미 만들어진 도구가 인터페이스와 맞지 않을 때 변환해서 연결
// 용도 2 : 아직 만들지 않은 도구를 미리 연결 (인터페이스가 없다면)
public class App {
public static void main(String[] args) {
Tiger tiger = new Tiger();
Mouse mouse = new Mouse();
RabbitAdapter rabbit = new RabbitAdapter(new OuterRabbit());
Doorman doorman = new Doorman();
doorman.쫓아내(rabbit);
}
}8) 결과

2️⃣ Mock 객체를 활용한 의존성 분리 설계 (어댑터 패턴 ❌)
1) Meter.java
C:\workspace\java_lab\designapp\src\mock\Meter.java
package mock;
public interface Meter {
int getStep();
}2) MockMeter.java
C:\workspace\java_lab\designapp\src\mock\MockMeter.java
package mock;
public class MockMeter implements Meter{
@Override
public int getStep() {
return 7;
}
}3) RealMeter.java
C:\workspace\java_lab\designapp\src\mock\lib\RealMeter.java
package mock.lib;
import mock.Meter;
// 백엔드 개발자가 만들 예정
public class RealMeter implements Meter {
@Override
public int getStep() {
// 1. 블루투스 연결
// 2. 프로토콜 지킨 통신으로 버퍼 다운
// 3. 리스너 구현
return 10;
}
}4) MeterService.java
C:\workspace\java_lab\designapp\src\mock\MeterService.java
package mock;
public class MeterService {
private Meter meter; // RealMeter, MockMeter
public MeterService(Meter meter) {
this.meter = meter;
}
public void render(){
int step = meter.getStep();
System.out.println("걸음수 "+step+" 만큼 그림 그리기 완료");
}
}5) App.java
C:\workspace\java_lab\designapp\src\mock\App.java
package mock;
import mock.lib.RealMeter;
/**
* 상황 : 만보기 라이브러리를 만드는 개발자, 만보기 메서드를 사용하는 프론트 개발자
* 문제 : 만보기 라이브러리 개발자가 일이 늦어서 30일 걸리고, 프론트 개발자는 10일만에 개발 해야됨.
* 프론트개발자(나) vs 백앤드개발자(동료)
*
* 아직 만들어지지 않았다면 Mock으로 구현!!
* -> 나중에 붙일 때 인터페이스가 없으면 어댑터로 연결해야 함
*/
public class App {
public static void main(String[] args) {
MeterService ms = new MeterService(new RealMeter());
ms.render();
}
}6) 결과

인터페이스가 있으면 이 방법! 인터페이스가 없다면 어댑터로!
Share article