Skip to main content

Adapter Pattern

View all Design Patterns

객체를 래핑(wrapping)하여 타 클래스와 호환이 가능하도록 하는 방법이다.

Class Diagram

Abstract overview

이때, Service 코드에는 타사 코드 등 변경할 수 없는 기존 레거시 코드가 포함된다.

Concrete example

이를 보면, 각각의 인증 방식(Naver, Google, Apple, Kakao)에 맞는 클래스를 각각의 어뎁터가 연관 관계(Aggregation)로 의존하고 있는 것을 알 수 있다. 또한 클라이언트는 AuthInterface만 의존하게 되기 때문에, 추가적인 인증 방식이 필요한 경우 해당 클래스와 어뎁터를 추가하면 된다.


Code

interface AuthInterface {
authenticate(): void;
getUserDetails(): void;
}

class NaverAuthAdapter implements AuthInterface {
private naverAuth: NaverAuth;

constructor(naverAuth: NaverAuth) {
this.naverAuth = naverAuth;
}

authenticate(): void {
this.naverAuth.authenticateWithNaver();
}

getUserDetails(): void {
this.naverAuth.getUser();
}
}

class GoogleAuthAdapter implements AuthInterface {
private googleAuth: GoogleAuth;

constructor(googleAuth: GoogleAuth) {
this.googleAuth = googleAuth;
}

authenticate(): void {
this.googleAuth.authenticateWithGoogle();
}

getUserDetails(): void {
this.googleAuth.getUser();
}
}

class AppleAuthAdapter implements AuthInterface {
private appleAuth: AppleAuth;

constructor(appleAuth: AppleAuth) {
this.appleAuth = appleAuth;
}

authenticate(): void {
this.appleAuth.authenticateWithApple();
}

getUserDetails(): void {
this.appleAuth.getUser();
}
}

class KakaoAuthAdapter implements AuthInterface {
private kakaoAuth: KakaoAuth;

constructor(kakaoAuth: KakaoAuth) {
this.kakaoAuth = kakaoAuth;
}

authenticate(): void {
this.kakaoAuth.authenticateWithKakao();
}

getUserDetails(): void {
this.kakaoAuth.getUser();
}
}

class NaverAuth {
/**
* Naver의 인증 로직 사용
*/
authenticateWithNaver() {
console.log("Authenticated by Naver");
}

getUser() {
console.log("Fetched Naver user");
}
}

class GoogleAuth {
/**
* Google의 인증 로직 사용
*/
authenticateWithGoogle() {
console.log("Authenticated by Google");
}

getUser() {
console.log("Fetched Google user");
}
}

class AppleAuth {
/**
* Apple의 인증 로직 사용
*/
authenticateWithApple() {
console.log("Authenticated by Apple");
}

getUser() {
console.log("Fetched Apple user");
}
}

class KakaoAuth {
/**
* Kakao의 인증 로직 사용
*/
authenticateWithKakao() {
console.log("Authenticated by Kakao");
}

getUser() {
console.log("Fetched Kakao user");
}
}

const googleAuth = new GoogleAuth();
const googleAdapter = new GoogleAuthAdapter(googleAuth);

googleAdapter.authenticate(); // Authenticated by Google
googleAdapter.getUserDetails(); // Fetched Google user

// ...

Pros and Cons

Pros

  • 타사 코드 등 변경할 수 없는 서비스 코드가 기존 코드에 영향을 주지 않으면서 사용이 가능하다.
  • 비즈니스 로직과 어뎁터 로직을 분리함으로써 SRP(Single Responsibility Principle, 단일책임원칙)를 준수한다.
  • 기존 코드(서비스 코드)의 재사용성이 향상된다.

Cons

  • 여러 인터페이스와 클래스를 생성해야 하기 떄문에, 코드의 복잡성이 커진다.
  • 기존 코드(서비스 코드)를 변경하는 것이 더 간단할 수 있다.
Related Links