Adapter Pattern

어댑터 패턴은 서로 호환되지 않는 인터페이스를 가진 클래스들이 함께 작동할 수 있도록 해주는 구조적 디자인 패턴이다. 이 패턴은 기존 코드를 수정하지 않고도 새로운 인터페이스와 함께 사용할 수 있게 해주는 중요한 역할을 한다.

일상생활에서 볼수 있는 것들 중 유사한 개념은, 전기 어댑터이다. 예를 들어, 대한민국에서는 220v 를 사용하지만, 일본에서는 110v 를 사용한다. 이때 전기를 공급받고자 사용하는 것이 전기어댑터이다.

구조

  • 타겟 인터페이스(Target Interface): 클라이언트가 사용하려는 인터페이스 (e.g. 외부 API)
  • 어댑터(Adapter): 타겟 인터페이스를 구현하고, 어댑티의 인터페이스를 호출하여 중간 역할을 수행
  • 어댑티(Adaptee): 변환되어야 할 기존 클래스 (기존 애플리케이션 코드에서 사용되던 클래스)
  • 클라이언트(Client): 타겟 인터페이스를 사용하는 객체

예시

// 기존 API 서비스 (어댑티)
class LegacyUserAPI {
  getUsers() {
    // 레거시 API에서 반환하는 데이터 형식
    return [
      { id: 1, username: "user1", fullName: "User One", role: "admin" },
      { id: 2, username: "user2", fullName: "User Two", role: "editor" }
    ];
  }
}

// 새로운 API 서비스 (어댑티)
class NewUserAPI {
  fetchUserList() {
    // 새로운 API에서 반환하는 데이터 형식
    return {
      status: "success",
      data: [
        { userId: 101, name: "John Doe", email: "john@example.com", permissions: ["read", "write"] },
        { userId: 102, name: "Jane Smith", email: "jane@example.com", permissions: ["read"] }
      ]
    };
  }
}

// 통합 사용자 API 어댑터 (타겟 인터페이스 구현)
class UserAPIAdapter {
  constructor(api) {
    this.api = api;
  }

  getUsers() {
    // LegacyUserAPI 어댑터
    if (this.api instanceof LegacyUserAPI) {
      const users = this.api.getUsers();
      return users.map(user => ({
        id: user.id,
        name: user.fullName,
        username: user.username,
        permissions: user.role === "admin" ? ["read", "write", "delete"] : ["read"]
      }));
    }
    // NewUserAPI 어댑터
    else if (this.api instanceof NewUserAPI) {
      const response = this.api.fetchUserList();
      if (response.status === "success") {
        return response.data.map(user => ({
          id: user.userId,
          name: user.name,
          username: user.email.split('@')[0],
          permissions: user.permissions
        }));
      }
      return [];
    }
  }
}

// 클라이언트 코드
const legacyAPI = new LegacyUserAPI();
const newAPI = new NewUserAPI();

const legacyAdapter = new UserAPIAdapter(legacyAPI);
const newAdapter = new UserAPIAdapter(newAPI);

console.log("Users from Legacy API (adapted):");
console.log(legacyAdapter.getUsers());

console.log("\nUsers from New API (adapted):");
console.log(newAdapter.getUsers());