13-3. 어댑터 패턴 (Adapter Pattern)

박은서's avatar
Feb 24, 2026
13-3. 어댑터 패턴 (Adapter Pattern)

1. 어댑터 패턴 (Adapter Pattern)

1️⃣ 어댑터 패턴이란?

1) 정의

호환되지 않는 인터페이스를 연결해주는 변환 패턴
서로 다른 형식의 코드를 직접 수정하지 않고 중간 변환 객체(어댑터)를 통해 연결

2) 핵심 개념

✔ 인터페이스 불일치 해결
✔ 기존 코드 수정 최소화
✔ 중간 변환 계층 추가
Client → Adapter → Adaptee

2️⃣ 비유로 이해하기

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) 결과

notion image

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) 결과

notion image

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) 결과

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