Search
Duplicate
🎨

[디자인 패턴 - 구조 패턴] 어댑터 패턴 (Adapter)

하나의 인터페이스를 클라이언트가 요구하는 다른 인터페이스로 변환할때 사용

1. 의도

GoF
클래스의 인터페이스를 사용자가 기대하는 인터페이스 형태로 적응(변환) 시킵니다.
서로 일치 하지 않는 인터페이스를 갖는 클래스들을 함께 동작 시킵니다.
Head First
특정 클래스 인터페이스를 클라이언트에서 요구하는 다른 인터페이스로 변환합니다.
인터페이스가 호환되지 않아 같이 쓸 수 없었던 클래스를 사용할 수 있게 도와줍니다.
하나의 인터페이스를 다른 인터페이스로 변환하는 용도로 사용합니다.

2. 활용성

기존 클래스를 사용하고 싶은데, 인터페이스가 맞지 않을 때
이미 만든 것을 재사용하고자 하나, 재사용 가능한 라이브러리를 수정할 수 없을 때
Object Adapter인 경우
이미 존재하는 여러 서브 클래스를 사용해야하는데, 서브 클래스의 상속을 통해 이들의 인터페이스를 다 개조한다는 것이 현실성이 없을 때
Object Adapter를 사용하여 부모 클래스의 인터페이스 변형하는게 더 바람직함

3. 구조

Class Adapter & Object Adapter
Object Adapter
Client는 Target 인터페이스를 구현한 Adaptee가 필요함.
Adaptee는 Target 인터페이스를 구현하고 있지 않는 독립된 객체이다.
따라서, Adapter를 통해 Adaptee가 Target 인터페이스를 구현할 수 있게 함

4. 참여자

참여자
역할
예시
Target
사용자가 사용할 응용 분야에 종속적인 인터페이스를 정의하는 클래스
Duck 클래스(인터페이스)
Client
인터페이스를 만족하는 객체와 동작할 대상
Turkey가 Duck처럼 동작하길 기대하는 대상
Adaptee
인터페이스의 적응이 필요한 기존 인터페이스를 정의하는 클래스 (적응 대상자)
Turkey 클래스(인터페이스)
Adapter
Target 인터페이스에 Adaptee의 인터페이스를 적응시키는 클래스
Duck 클래스에 맞춰 Turkey 클래스(인터페이스)를 변환해줌

5. 협력 방법

사용자는 Adapter에 해당하는 클래스의 인스턴스에게 연산을 호출하고, Adapter는 해당 요청을 수행하기 위해 Adaptee의 연산을 호출합니다.

6. 결과

class adapter
Adapter 클래스는 Adaptee 클래스를 Target 클래스로 변형하는데, 이를 위해서 Adaptee 클래스를 상속 받아야 함
하나의 클래스와 이 클래스를 의 모든 서브 클래스들을 개조할 때라면 클래스 어댑터 방식 사용 불가
Adapter 클래스는 Adaptee 클래스를 상속하기 때문에, Adaptee에 정의된 행동을 재정의 할 수 있음
한개의 객체(Adapter)만 사용하며, Adaptee로 가기 위한 추가적인 포인터 간접화가 필요하지 않음
object adapter
Adapter 클래스는 하나만 존재해도 수많은 Adaptee 클래스들과 동작할 수 있음
Adapter 클래스의 행동을 재정의하기가 매우 어려움
Adaptee 클래스를 상속받아서 새로운 서브 클래스를 만듦
Adapter 클래스는 Adaptee 클래스가 아닌 Adaptee 클래스의 서브 클래스를 참조해야함

7. 예시 코드

/** * The Target defines the domain-specific interface used by the client code. */ class Target { public request(): string { return 'Target: The default target\'s behavior.'; } } /** * The Adaptee contains some useful behavior, but its interface is incompatible * with the existing client code. The Adaptee needs some adaptation before the * client code can use it. */ class Adaptee { public specificRequest(): string { return '.eetpadA eht fo roivaheb laicepS'; } } /** * The Adapter makes the Adaptee's interface compatible with the Target's * interface. */ class Adapter extends Target { private adaptee: Adaptee; constructor(adaptee: Adaptee) { super(); this.adaptee = adaptee; } public request(): string { const result = this.adaptee.specificRequest().split('').reverse().join(''); return `Adapter: (TRANSLATED) ${result}`; } } /** * The client code supports all classes that follow the Target interface. */ function clientCode(target: Target) { console.log(target.request()); } console.log('Client: I can work just fine with the Target objects:'); const target = new Target(); clientCode(target); console.log(''); const adaptee = new Adaptee(); console.log('Client: The Adaptee class has a weird interface. See, I don\'t understand it:'); console.log(`Adaptee: ${adaptee.specificRequest()}`); console.log(''); console.log('Client: But I can work with it via the Adapter:'); const adapter = new Adapter(adaptee); clientCode(adapter);
TypeScript
복사