Adapter pattern

[ Programming > Design Pattern ]

[디자인 패턴] 어댑터 패턴

 Carrot Yoon
 2025-09-05
 2

어댑터 패턴(Adapter pattern)

1. 어댑터 패턴이란

어댑터 패턴은 호환되지 않는 인터페이스를 가진 클래스들이 함께 작동할 수 있도록 해주는 구조적 디자인 패턴이다. 실생활에서 전원 어댑터가 서로 다른 플러그 규격을 연결해주는 것처럼, 소프트웨어에서도 서로 다른 인터페이스를 가진 객체들을 연결해주는 역할을 한다.

어댑터 패턴은 주로 다음과 같은 경우 유용하다.

  • 기존 코드를 수정할 수 없는 상황에서 새로운 라이브러리나 API를 사용해야 할 때

  • 서드파티 라이브러리의 인터페이스가 기존 시스템과 맞지 않을 때

  • 레거시 시스템과 새로운 시스템을 통합해야 할 때

  • 데이터 형식이나 메서드 시그니처가 다른 클래스들을 통합해야 할 때

2. 어댑터 패턴 구조

  1. Target: 클라이언트가 사용하는 인터페이스

  2. Adapter: Target 인터페이스를 구현하고 Adaptee를 감싸는 클래스

  3. Adaptee: 어댑터가 감싸는 기존 클래스 (호환되지 않는 인터페이스를 가짐)

  4. Client: Target 인터페이스를 통해 객체와 협력하는 클래스

3. 어댑터 패턴 예시 코드

// Target 인터페이스 - 클라이언트가 기대하는 인터페이스interface MediaPlayer {    void play(String audioType, String fileName);}// Adaptee - 기존에 존재하는 호환되지 않는 클래스class AdvancedMediaPlayer {    void playVlc(String fileName) {        System.out.println("Playing vlc file: " + fileName);    }        void playMp4(String fileName) {        System.out.println("Playing mp4 file: " + fileName);    }}// Adapter - Target 인터페이스와 Adaptee를 연결class MediaAdapter implements MediaPlayer {    private AdvancedMediaPlayer advancedPlayer;        public MediaAdapter(String audioType) {        if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {            advancedPlayer = new AdvancedMediaPlayer();        }    }        @Override    public void play(String audioType, String fileName) {        if (audioType.equalsIgnoreCase("vlc")) {            advancedPlayer.playVlc(fileName);        } else if (audioType.equalsIgnoreCase("mp4")) {            advancedPlayer.playMp4(fileName);        }    }}// Client 클래스class AudioPlayer implements MediaPlayer {    private MediaAdapter mediaAdapter;        @Override    public void play(String audioType, String fileName) {        if (audioType.equalsIgnoreCase("mp3")) {            System.out.println("Playing mp3 file: " + fileName);        } else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {            mediaAdapter = new MediaAdapter(audioType);            mediaAdapter.play(audioType, fileName);        } else {            System.out.println("Invalid media. " + audioType + " format not supported");        }    }}

// 다양한 데이터베이스 드라이버를 통일된 인터페이스로 사용interface DatabaseConnection {    void connect();    void executeQuery(String query);}class MySQLAdapter implements DatabaseConnection {    private MySQLDriver mysqlDriver;        public MySQLAdapter(MySQLDriver driver) {        this.mysqlDriver = driver;    }        @Override    public void connect() {        mysqlDriver.mysqlConnect();    }        @Override    public void executeQuery(String query) {        mysqlDriver.mysqlQuery(query);    }}

4. 마무리

어댑터 패턴은 소프트웨어 개발에서 호환성 문제를 우아하게 해결해주는 중요한 디자인 패턴이다. 특히 기존 시스템을 유지하면서 새로운 기능을 통합해야 하는 상황에서 매우 유용하다.

마지막으로 장단점을 정리하고 끝내겠다.

  • 장점

    • 개방-폐쇄 원칙 준수: 기존 코드를 수정하지 않고 새로운 기능 추가 가능

    • 단일 책임 원칙 준수: 인터페이스 변환 로직을 별도 클래스로 분리

    • 코드 재사용성 향상: 기존 코드를 새로운 환경에서 재사용 가능

    • 유연성 증대: 런타임에 어댑터 교체 가능

  • 단점

    • 코드 복잡성 증가: 새로운 인터페이스와 클래스 추가 필요

    • 성능 오버헤드: 추가적인 메서드 호출로 인한 미미한 성능 저하

    • 디버깅 어려움: 호출 체인이 길어져 디버깅이 복잡해질 수 있음