ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 어댑터 패턴(Adapter Pattern)이란?
    Design Pattern/구조 디자인 패턴 2024. 4. 14. 14:55
    반응형

     어댑터 패턴은 서로 호환되지 않는 인터페이스를 가진 클래스들이 함께 작동할 수 있도록 하는 구조적 디자인 패턴입니다. 이 패턴은 기존 시스템과 새 시스템, 라이브러리 또는 애플리케이션 간의 인터페이스 차이를 극복하기 위해 중간에 어댑터 클래스를 사용하여 호환성 문제를 해결합니다.

    1. 어댑터 패턴은 주로 어디에 쓰이나?

    어댑터 패턴은 주로 다음과 같은 상황에서 사용됩니다:

    • 기존 시스템과 새 시스템 간의 통합: 다른 인터페이스를 가진 두 시스템이 서로 통신해야 할 때.
    • 라이브러리 교체: 기존 코드를 변경하지 않고 새로운 라이브러리 또는 도구를 기존 시스템에 통합할 때.
    • 플랫폼 독립적인 코드 작성: 다양한 플랫폼에서 작동하는 코드를 개발할 때.

    2. Java와 Go로 어댑터 패턴을 구현할 때의 차이점

    • Java: Java에서는 클래스 상속 또는 인터페이스를 사용하여 어댑터 패턴을 구현할 수 있습니다. 일반적으로 인터페이스를 통한 구현이 선호됩니다.
    • Go: Go는 상속을 지원하지 않으며, 인터페이스만을 사용하여 어댑터 패턴을 구현합니다. 구조체와 인터페이스를 함께 사용하여 동일한 기능을 제공합니다.

    3. 어댑터 패턴 예시

    Java 예시:

    // Target Interface
    interface MediaPlayer {
        void play(String audioType, String fileName);
    }
    
    // Adaptee
    class AdvancedMediaPlayer {
        public void playVlc(String fileName) {
            System.out.println("Playing vlc file. Name: " + fileName);
        }
        public void playMp4(String fileName) {
            System.out.println("Playing mp4 file. Name: " + fileName);
        }
    }
    
    // Adapter
    class MediaAdapter implements MediaPlayer {
        AdvancedMediaPlayer advancedMusicPlayer;
    
        public MediaAdapter(String audioType) {
            if (audioType.equalsIgnoreCase("vlc")) {
                advancedMusicPlayer = new AdvancedMediaPlayer();
            } else if (audioType.equalsIgnoreCase("mp4")) {
                advancedMusicPlayer = new AdvancedMediaPlayer();
            }
        }
    
        @Override
        public void play(String audioType, String fileName) {
            if (audioType.equalsIgnoreCase("vlc")) {
                advancedMusicPlayer.playVlc(fileName);
            } else if (audioType.equalsIgnoreCase("mp4")) {
                advancedMusicPlayer.playMp4(fileName);
            }
        }
    }
    
    // Client
    class AudioPlayer implements MediaPlayer {
        MediaAdapter mediaAdapter;
    
        @Override
        public void play(String audioType, String fileName) {
            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");
            }
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            AudioPlayer audioPlayer = new AudioPlayer();
    
            audioPlayer.play("mp3", "beyond the horizon.mp3");
            audioPlayer.play("mp4", "alone.mp4");
            audioPlayer.play("vlc", "far far away.vlc");
            audioPlayer.play("avi", "mind me.avi");
        }
    }
    1. 인터페이스 정의:
      • MediaPlayer 인터페이스는 play 메소드를 정의합니다. 이 메소드는 음악 파일의 타입과 파일 이름을 매개변수로 받습니다.
    2. Adaptee 클래스:
      • AdvancedMediaPlayer 클래스는 VLC와 MP4 파일을 재생하는 기능을 가집니다. 이 클래스는 playVlc와 playMp4 메소드를 포함하여 각각의 파일 타입에 대한 재생 로직을 구현합니다.
    3. Adapter 클래스:
      • MediaAdapter 클래스는 MediaPlayer 인터페이스를 구현하며, AdvancedMediaPlayer 객체를 사용하여 다양한 파일 형식을 재생합니다. 이 어댑터는 audioType에 따라 적절한 메소드를 호출하여 파일을 재생합니다.
    4. Client 클래스:
      • AudioPlayer 클래스는 기본적으로 MediaPlayer 인터페이스를 구현합니다. 특정 파일 타입을 재생할 때 MediaAdapter를 사용하여 필요한 형식에 맞게 파일을 재생할 수 있습니다. 지원하지 않는 파일 형식에 대해선 오류 메시지를 출력합니다.

     

    Go 예시:

    package main
    
    import "fmt"
    
    // Target interface
    type MediaPlayer interface {
        Play(audioType, fileName string)
    }
    
    // Adaptee
    type AdvancedMediaPlayer struct{}
    
    func (amp *AdvancedMediaPlayer) PlayVLC(fileName string) {
        fmt.Println("Playing vlc file. Name:", fileName)
    }
    
    func (amp *AdvancedMediaPlayer) PlayMP4(fileName string) {
        fmt.Println("Playing mp4 file. Name:", fileName)
    }
    
    // Adapter
    type MediaAdapter struct {
        advancedMusicPlayer *AdvancedMediaPlayer
    }
    
    func NewMediaAdapter(audioType string) *MediaAdapter {
        adapter := &MediaAdapter{
            advancedMusicPlayer: &AdvancedMediaPlayer{},
        }
        return adapter
    }
    
    func (adapter *MediaAdapter) Play(audioType, fileName string) {
        if audioType == "vlc" {
            adapter.advancedMusicPlayer.PlayVLC(fileName)
        } else if audioType == "mp4" {
            adapter.advancedMusicPlayer.PlayMP4(fileName)
        }
    }
    
    // Client
    type AudioPlayer struct{}
    
    func (player *AudioPlayer) Play(audioType, fileName string) {
        if audioType == "vlc" || audioType == "mp4" {
            adapter := NewMediaAdapter(audioType)
            adapter.Play(audioType, fileName)
        } else {
            fmt.Println("Invalid media. ", audioType, " format not supported")
        }
    }
    
    func main() {
        player := &AudioPlayer{}
        player.Play("mp4", "myVideo.mp4")
        player.Play("vlc", "myMusic.vlc")
    }
    1. 인터페이스 정의:
      • Go에서는 MediaPlayer 인터페이스를 정의하여 Play 메소드를 포함합니다. 이 메소드는 오디오 타입과 파일 이름을 매개변수로 받습니다.
    2. Adaptee 구조체:
      • AdvancedMediaPlayer 구조체는 PlayVLC와 PlayMP4 메소드를 통해 VLC와 MP4 파일 재생을 지원합니다.
    3. Adapter 구조체:
      • MediaAdapter 구조체는 MediaPlayer 인터페이스를 구현합니다. 이 구조체는 AdvancedMediaPlayer를 포함하며, 생성자 NewMediaAdapter를 통해 초기화됩니다. Play 메소드를 통해 파일 타입에 맞는 재생 함수를 호출합니다.
    4. Client 구조체:
      • AudioPlayer 구조체는 MediaPlayer 인터페이스를 구현하고, 지원하는 파일 형식을 확인하여 MediaAdapter를 사용해 파일을 재생합니다. 지원하지 않는 형식일 경우 오류 메시지를 출력합니다.

     이러한 방식으로, Java와 Go 둘 다에서 어댑터 패턴을 활용하여 다양한 오디오 파일 타입을 처리하는 능력을 소프트웨어에 통합할 수 있습니다. 어댑터는 기존 코드와 새로운 코드 사이에서 호환성을 제공하는 중간자 역할을 수행하여 코드의 재사용성과 유지보수성을 높여줍니다.

    4. 어댑터 패턴의 장단점

    장점:

    • 기존 코드 변경 없이 새로운 인터페이스를 소프트웨어에 통합할 수 있습니다.
    • 기존 클래스가 예상하지 못한 환경에서 재사용될 수 있습니다.

    단점:

    • 전체 시스템의 복잡성이 증가할 수 있습니다.
    • 때때로 많은 추가 객체의 생성이 필요하여, 시스템의 오버헤드가 늘어날 수 있습니다.

     

    반응형
Designed by Tistory.