학습일지/Language

[Design Pattern] Adapter

inspirit941 2020. 12. 18. 08:17
반응형

Adapter Pattern

한 클래스의 인터페이스를, 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환하는 역할.

인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스를 연결하는 역할.

  • 이미 제공되어 있는 것 / 필요한 것 사이의 차이를 없앤다고 보면 된다
  • Wrapper 패턴이라고도 불림. 다른 용도로 사용할 수 있도록 변경해주는 개념

두 가지 종류가 있다.

  • Class 기반 Adapter (상속을 사용한 방법)
  • Instance 기반 Adapter (위임을 사용한 방법)

기존의 클래스를 개조해서 필요한 클래스를 생성하는 방법.

일반적으로 기존의 클래스 == "잘 만들어졌고, 버그가 발생하지 않는다는 걸 오랜 시간 사용하며 증명한 코드". 이 클래스를 더 많은 곳에서 다양한 방식으로 사용하기 위해 고안한 게 Adapter 패턴.

  • 이미 있는 클래스를 사용하므로, 필요한 메소드를 빠르게 생성할 수 있음
  • 버그가 발생해도 기존 클래스에는 버그가 없을 가능성이 크므로, Adapter 클래스 위주로 디버깅하면 된다.

이미 만들어진 클래스를 새 인터페이스에 맞게 개조할 때...

  • Adapter를 사용하지 않고 기존 클래스를 수정할 경우: 동작 테스트가 이미 끝난, 통과했던 테스트들을 전부 다시 실행해봐야 함.
  • Adpater를 사용할 경우: 기존 클래스는 그대로 두고 원하는 인터페이스만 맞추는 형태이므로, 기존 클래스의 인터페이스만 제대로 안다면 생성해 사용할 수 있음.
public interface APlayer {
    void play(String fileName);
    void stop();
}

public class APlayerImpl implements APlayer {
    @Override
    public void play(String fileName) {
        System.out.println("(A) " + fileName);
    }
    @Override
    public void stop() {
    }
}

public interface BPlayer {
    void playFile(String fileName);
    void StopFile();
}


public class BPlayerImpl implements BPlayer {
    @Override
    public void play(String fileName) {
        System.out.println("(B) " + fileName);
    }
    @Override
    public void stop() {
    }
}

public class TestAdapterPattern {
    public static void main(String[] args) {
        APlayer aplayer = new APlayerImpl();
        player.play("test.mp3");
        // 계약기간 만료로 이전까지의 APlayerImpl는 사용할 수 없다고 가정.

        // 새로 도입된 BPlayer방식을 사용해야 할 경우
        // APlayer로 잘 작동하던 코드를 최대한 변경없이 사용하고자 함
        aplayer = new BtoAAdapter(new BPlayerImpl());
        aplayer.play("test2.mp3");

        // 모든 코드가 Aplayer 인터페이스에 맞춰져 있으므로
        // 전체 코드를 BPlayer로 변경하는 대신, BPlayer로 변환하는 어댑터 클래스만 제대로 생성하면 된다.
    }
}

// Adapter
// 기존 코드에서 수정해야 할 부분을 Adapter에서 적용함.
// 기존에 잘 쓰이던 클래스이므로, 버그 발생 시 Adapter 부분만 확인하면 된다.
public class BtoAAdapter implements APlayer {
    private BPlayer media;

    public BtoAAdapter(BPlayer media) { this.media = media; }

    @Override
    public void play(String fileName) {
        System.out.println("Using Adapter : ");
        media.playFile(fileName);
    }
    @Override
    public void stop(){}
}

만약 BPlayer가 Abstract Class라면

public abstract class BPlayer {
    public abstract void playFile(String fileName);
    public abstract void StopFile();
}

public class BPlayerImpl extends BPlayer {
    @Override
    public void play(String fileName) {
        System.out.println("(B) " + fileName);
    }
    @Override
    public void stop() {
    }
}

public class BtoAAdapter extends BPlayerImpl implements APlayer {
    private BPlayer media;

    public BtoAAdapter(BPlayer media) { this.media = media; }

    @Override
    public void play(String fileName) {
        System.out.println("Using Adapter : ");
        media.playFile(fileName);
    }
    @Override
    public void stop(){}
}
반응형