Adapter Design Pattern,将类的接口转换为客户期待的另外一个接口,使接口不兼容的对象能够相互合作。
使用场景
- 原有接口功能不满足现有需求,在兼容老接口的同时做适当扩展
- 相似接口间做功能的统一
- 不同数据格式、不同协议需要转换
- when new components need to be integrated and work together with existing components in the application
- parts of the program are rewritten with an improved interface, but the old code still expects the original interface
when you have a third party API that there is a chance it changes ```javascript // 假设你有两个接口相互兼容的类:圆孔(RoundHole)和圆钉(RoundPeg)。 class RoundHole is constructor RoundHole(radius) { … }
method getRadius() is
// 返回孔的半径。
method fits(peg: RoundPeg) is
return this.getRadius() >= peg.getRadius()
class RoundPeg is constructor RoundPeg(radius) { … }
method getRadius() is
// 返回钉子的半径。
// 但还有一个不兼容的类:方钉(SquarePeg)。 class SquarePeg is constructor SquarePeg(width) { … }
method getWidth() is
// 返回方钉的宽度。
// 适配器类让你能够将方钉放入圆孔中。它会对 RoundPeg 类进行扩展,以接收适 // 配器对象作为圆钉。 class SquarePegAdapter extends RoundPeg is // 在实际情况中,适配器中会包含一个 SquarePeg 类的实例。 private field peg: SquarePeg
constructor SquarePegAdapter(peg: SquarePeg) is
this.peg = peg
method getRadius() is
// 适配器会假扮为一个圆钉,
// 其半径刚好能与适配器实际封装的方钉搭配起来。
return peg.getWidth() * Math.sqrt(2) / 2
// 客户端代码中的某个位置。 hole = new RoundHole(5) rpeg = new RoundPeg(5) hole.fits(rpeg) // true
small_sqpeg = new SquarePeg(5) large_sqpeg = new SquarePeg(10) hole.fits(small_sqpeg) // 此处无法编译(类型不一致)。
small_sqpeg_adapter = new SquarePegAdapter(small_sqpeg) large_sqpeg_adapter = new SquarePegAdapter(large_sqpeg) hole.fits(small_sqpeg_adapter) // true hole.fits(large_sqpeg_adapter) // false
```javascript
/**
* 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);