Adapter

클래스의 인터페이스를 사용자가 기대하는 인터페이스 형태로 적응(변환)시킨다.

서로 일치하지 않는 인터페이스를 갖는 클래스들을 함께 동작시킨다.

adapter

  • Target

    사용자가 사용할 응용 분야에 종속적인 인터페이스를 정의하는 클래스

  • Client

    Target 인터페이스를 만족하는 객체와 동작할 대상

  • Adaptee

    인터페이스의 적응이 필요한 기존 인터페이스를 정의하는 클래스, Adapte 대상자

  • Adapter

    Target 인터페이스에 Adaptee의 인터페이스를 적응 시키는 클래스

1. 문제 상황

그림 편집기를 구현하려고 한다.

추상 클래스 Shape를 만들고 LineShape, PolygonShape등의 클래스를 개발한다.

interface Shape {
  // 두 점을 받아 bound box를 생성
  boundingBox: (bottomLeft: Point, topRight: Point) => void;

  // 객체를 드래그하는 기능을 하는 manipulator 반환
  createManipulator: () => Manipulator;
}

class LineShape implements Shape {
  private bottomLeft: Point;
  private topRight: Point;
  boundingBox(bottomLeft: Point, topRight: Point) {
    this.bottomLeft = bottomLeft;
    this.topRight = topRight;
  }
  createManipulator() {
    return new Manipulator();
  }
}

여기에 TextShape를 추가한다고 하자. Text는 Line, Polygon에 비해 복잡하다. 그리고 기존에 출시된 TextView 처리 시스템이 있다면 때문에 이를 재사용 하는것이 바람직하다.

class TextView {
  private x: Coord;
  private y: Coord;
  // 두 점으로 line 생성
  setOrigin(x: Coord, y: Coord) {
    this.x = x;
    this.y = y;
  }
  // 기존의 두 점을 넓혀 box 생성
  getExtend(width: Coord, height: Coord) {
    this.x.extend(width);
    this.y.extend(height);
  }
  isEmpty() {}
}

하지만 우리가 만든 추상 클래스 Shape에 맞춰서 개발된 것이 아니기 때문에 바로 적용하기는 힘들다. TextView 인터페이스를 변경하여 Shape의 인터페이스와 일치하도록 만들어야 한다.

2. Adapter

TextShape는 TextView를 통해 부모 클래스에 정의된 구현을 전달받고, Shape를 통해 부모 클래스(인터페이스)에 정의된 메소드를 구현해야 한다.

  • TextView를 상속받을 때 Private 상속을 사용하는게 좋은데 TextView가 TextShape에 노출되는것을 막기 위해서이다.

    typescript에서는 방법이 없는것 같다……

class TextShape extends TextView implements Shape {
  private bottomLeft: Point;
  private topRight: Point;
  boundingBox(bottomLeft: Point, topRight: Point) {
    const { bottom, left, width, height } = getCoord(bottomLeft, topRight);
    this.setOrigin(bottom, left);
    this.getExtend(width, height);

    bottomLeft = new Point(bottom, left);
    topRight = new Point(bottom + innerHeight, left + width);
  }
  createManipulator() {
    return new TextManipulator();
  }
}
  1. TextView의 setOrigingetExtend를 조합하여 boundingBox를 사용 가능하도록 만들고

  2. TextView에서 지원하지 않는 createManipulator기능을 직접 구현하여 제공하였다.

추가로, TextView를 상속받는 방법이 아니라 생성자나 함수를 통해 주입받아서 사용하는 방식으로 구현할 수도 있다.