2025-04-03 Adapter pattern

성현규·2025년 4월 3일
post-thumbnail

1. Adapter pattern

  • 서로 다른 인터페이스를 가진 클래스들을 기존 시스템의 인터페이스에 맞추기 위해 어댑터 패턴을 적용한다.

📌 1-1. 이미지 변환기 만들기 (기초)

🔍 핵심 개념 및 주의할 점

  • 서로 다른 인터페이스를 가진 클래스들을 기존 시스템의 인터페이스에 맞추기 위해 어댑터 패턴을 적용한다.
  • 어댑터는 기존 인터페이스를 구현하고, 내부에 실제 기능을 제공하는 객체(Adaptee)를 필드로 가지고 있다.
  • 클라이언트는 어댑터를 통해 일관된 방식으로 다양한 클래스를 사용할 수 있다.

🧠 기억해야 할 패턴 또는 로직 흐름

  • ImageViewer라는 인터페이스를 정의하고, 시스템은 이 인터페이스만을 신뢰한다.
  • 각 이미지 클래스(PngImage, JpegImage, GifImage)는 고유 메서드를 제공하지만, ImageViewer와 호환되지 않는다.
  • 각 이미지 클래스마다 별도의 어댑터(PngAdapter, JpegAdapter, GifIAdapter)를 정의하고, 이들은 ImageViewer를 구현한다.
  • 어댑터는 생성자에서 해당 이미지 객체를 주입받고, display() 메서드에서 그 객체의 기능 메서드를 호출한다.
public class Main {
    public static void main(String[] args) {
        ImageViewer[] box = new ImageViewer[3];
        box[0] = new PngAdapter(new PngImage());
        box[1] = new JpegAdapter(new JpegImage());
        box[2] = new GifIAdapter(new GifImage());

        for (ImageViewer i : box){
            i.display();
        }
    }
}

// 기존 이미지 뷰어
interface ImageViewer {
    public abstract void display(); // public abstract는 생략되곤 한다. default를 붙이면(안붙이면 abstract가 자동이므로) 상속자가 선택적으로 오버라이드할 수 잇다.
}

// 이미지 클래스
class PngImage {
    public void renderPng(){
        System.out.println("PNG 이미지를 렌더링합니다.");
    }
}
class JpegImage {
    public void drawJpeg(){
        System.out.println("JPEG 이미지를 그립니다.");
    }
}
class GifImage {
    public void animateGif() {
        System.out.println("GIF 애니메이션을 실행합니다.");
    }
}

// 어뎁터 클래스 <- 기존이미지 뷰어의 display로 각 이미지 클래스가 작동할 수 있게함.
class PngAdapter implements ImageViewer{
    private PngImage png; // 연결시킬 클래스의 객체를 필드값으로 갖는다.

    PngAdapter(PngImage png){
        this.png = png;
    }

    @Override
    public void display() { // 기존의 작동방식으로 새로운 기능을 구현
    png.renderPng();
    }
}
class JpegAdapter implements ImageViewer{
    private JpegImage jpeg;

    JpegAdapter(JpegImage  jpeg){
        this.jpeg = jpeg;
    }

    @Override
    public void display() {
    jpeg.drawJpeg();
    }
}
class GifIAdapter implements ImageViewer{
    private GifImage gif;

    GifIAdapter(GifImage gif){
        this.gif = gif;
    }

    @Override
    public void display() {
        gif.animateGif();
    }
}

📌 1-2. 오디오 통합 컨트롤러 시스템

🔍 핵심 개념 및 주의할 점

  • 서로 다른 외부 라이브러리(Mp3Service, FlacEngine, OggTool)를 통합 인터페이스(AudioControlUnit)로 일관되게 제어하는 어댑터 패턴을 구현하였다.
  • 각 어댑터 클래스는 상태 활성화, 재생, 로그 저장 등의 공통 기능을 인터페이스로 추상화하여 클라이언트 코드(Main)가 특정 구현에 의존하지 않도록 구성하였다.
  • instanceof를 통해 각 어댑터의 고유 기능(setEqualizer, boostVolume)을 조건적으로 처리하였다.

🧠 기억해야 할 패턴 또는 로직 흐름

  • (1단계 → 어댑터 패턴으로 인터페이스 통합)
    외부 라이브러리 클래스는 각기 다른 메서드와 상태 명칭을 가지므로, AudioControlUnit 인터페이스로 추상화한 어댑터 클래스를 구현한다.

  • (2단계 → 클라이언트에서 인터페이스 기반 처리)
    List<AudioControlUnit> 형태로 어댑터들을 저장하고, play, activate, logPlay 메서드를 반복문으로 호출함으로써 포맷에 관계없는 일관된 재생 흐름을 구성한다.

  • (3단계 → 개별 포맷별 고유 기능 분기 처리)
    instanceof로 타입을 체크한 후 Mp3Adapter의 setEqualizer, FlacAdapter의 boostVolume 등 추가 기능을 조건적으로 수행한다.


public class Main {
    public static void main(String[] args) {
        List<AudioControlUnit> box = new ArrayList<>();
        box.add(new Mp3Adapter(new Mp3Service()));
        box.add(new FlacEngineAdapter(new FlacEngine()));
        box.add(new OggToolAdapter(new OggTool()));

        for (AudioControlUnit i : box) {
            i.play();
            i.activate();
            i.logPlay();
        }

        System.out.println("---------------------");
        
        for (AudioControlUnit i : box) {
            System.out.println(i.getFormatName());
            System.out.println(i.isActive() ? "활성":"비활성");
            i.getLog();
            if (i instanceof Mp3Adapter){
                ((Mp3Adapter)i).setEqualizer("Bass");
            }

            else if (i instanceof FlacEngineAdapter) {
                ((FlacEngineAdapter) i).boostVolume(50);
            }
        }
}
}

// 기존 인터페이스
interface AudioControlUnit {
    void play();
    String getFormatName();
    boolean isActive();
    void activate();
    void logPlay();
    String getLog();
}

// 외부 라이브러리들(이라하자 하는 클래스)
class Mp3Service {
    private boolean enabled = false;

    public boolean isEnabled() {
        return enabled;
    }

    public void mp3Play(){
        System.out.println("mp3가 재생됩니다.");
    }

    public String getMp3Type(){
        return "MP3";
    }

    public void setEqualizer(String mode){
        System.out.printf("%s모드로 세팅되었습니다.\n", mode);
    }

    public void turnMp3(){
        if (enabled) enabled = false;
        else enabled = true;
    }

    public boolean MP3status(){
        return enabled;
    }
}
class FlacEngine {
    private boolean enabled = false;
    public boolean isEnabled() {
        return enabled;
    }

    void executeFlac() {
        System.out.println("Flac을 실행합니다.");
    }

    String format(){
        return "FLAC";
    }

    void boostVolume(int level){
        System.out.printf("볼륨을 %d로 조정합니다.\n", level);
    }

    public void turnFlac(){
        if (enabled) enabled = false;
        else enabled = true;
    }

    public boolean Flacstatus(){
        return enabled;
    }

}
class OggTool {
    private boolean enabled = false;
    public boolean isEnabled() {
        return enabled;
    }

    void runOgg(){
        System.out.println("ogg를 실행합니다.");
    }

    String info(){
        return "OGG";
    }

    public void turnOgg(){
        if (enabled) enabled = false;
        else enabled = true;
    }

    public boolean Oggstatus(){
        return enabled;
    }
}

// 기존 인터페이스에 외부 라이브러리를 연결시키기 위한 어댑터 클래스
class Mp3Adapter implements AudioControlUnit {
    private Mp3Service mp3;

    List <LocalDateTime> list = new ArrayList(); 


    public Mp3Adapter(Mp3Service mp3) {
        this.mp3 = mp3;
    }

    void setEqualizer(String mode){
        if (mp3.isEnabled()){
        System.out.printf("EQ를 %s로 설정합니다.\n", mode);
        }
    }

    @Override
    public void activate() {
        mp3.turnMp3();
        System.out.println("mp3가 활성화되었습니다.");
    }

    @Override
    public String getFormatName() {
        return mp3.getMp3Type();
    }

    @Override
    public String getLog() {
        return list.get(list.size()-1).toString();
    }

    @Override
    public boolean isActive() {
        return mp3.MP3status();
    }

    @Override
    public void logPlay() {
        list.add(LocalDateTime.now());
    }

    @Override
    public void play() {
        mp3.mp3Play();
    }
}
class FlacEngineAdapter implements AudioControlUnit {
    private FlacEngine flacEngine;
    List <LocalDateTime> list = new ArrayList();

    public FlacEngineAdapter(FlacEngine flacEngine) {
        this.flacEngine = flacEngine;
    }

    @Override
    public void activate() {
        flacEngine.turnFlac();
        System.out.println("Flac이 활성화되었습니다.");
    }

    @Override
    public String getFormatName() {
        return flacEngine.format();
    }

    @Override
    public String getLog() {
        return list.get(list.size()-1).toString();
    }

    @Override
    public boolean isActive() {
        return flacEngine.Flacstatus();
    }

    @Override
    public void logPlay() {
        list.add(LocalDateTime.now());
    }

    @Override
    public void play() {
        flacEngine.executeFlac();
    }
    
    public void boostVolume(int level){
        if (flacEngine.isEnabled()){
            System.out.printf("볼륨을 %s로 설정합니다.\n", level);
        }
    }
}
class OggToolAdapter implements AudioControlUnit {
    private OggTool oggTool;
    List <LocalDateTime> list = new ArrayList();

    public OggToolAdapter(OggTool oggTool) {
        this.oggTool = oggTool;
    }

    @Override
    public void activate() {
        oggTool.turnOgg();
        System.out.println("ogg가 활성화되었습니다.");
    }

    @Override
    public String getFormatName() {
        return oggTool.info();
    }

    @Override
    public String getLog() {
        return list.get(list.size()-1).toString();
    }

    @Override
    public boolean isActive() {
        return oggTool.Oggstatus();
    }

    @Override
    public void logPlay() {
        list.add(LocalDateTime.now());
    }

    @Override
    public void play() {
        oggTool.runOgg();
    }
}
profile
학생

0개의 댓글