하나의 인터페이스를 클라이언트가 요구하는 다른 인터페이스로 변환할때 사용
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
복사