概念
通常,客户类通过类的接口访问它提供的服务。有时,现有的类可以提供客户类需要的功能,但它所提供的接口不一定是客户类所期望的——可能接口过于详细、缺少细节,或者名称不匹配。
在这种情况下,需要将现有接口转化为客户类期望的接口,从而保证对现有类的重用。适配器模式(Adapter Pattern)通过定义一个包装类来完成这种转化:
- Target:客户类期望的接口
- Adaptee:现有的、接口不兼容的类
- Adapter:包装 Adaptee,实现 Target 接口
当客户类调用 Adapter 的方法时,Adapter 内部转而调用 Adaptee 的对应方法,这个过程对客户类透明。
类适配器 vs 对象适配器
| 类适配器 | 对象适配器 | |
|---|---|---|
| 实现方式 | 继承 Adaptee | 组合 Adaptee |
| 灵活性 | 静态绑定,无法适配 Adaptee 子类 | 可适配 Adaptee 及其所有子类 |
| 方法重载 | 可重载 Adaptee 的方法 | 不能直接重载,但可在包装方法中修改行为 |
| 可见性 | 客户类可见 Adaptee 的 public 方法 | 客户类与 Adaptee 完全解耦 |
| Java 限制 | 仅适用于 Target 是接口(Java 单继承) | Target 可以是接口或抽象类 |
类适配器示例
Adapter 通过继承 Adaptee 来复用其接口:
// Target:客户类期望的接口
public interface Target {
void sampleOperation1();
}
// Adaptee:现有的第三方类,接口不兼容
public class Adaptee {
public void sampleOperation2() {
System.out.println("Adaptee.sampleOperation2()");
}
}
// Adapter:继承 Adaptee,实现 Target
public class Adapter extends Adaptee implements Target {
@Override
public void sampleOperation1() {
this.sampleOperation2();
}
}
// Client
public class Client {
public static void main(String[] args) {
Target target = new Adapter();
target.sampleOperation1();
}
}
对象适配器示例
Adapter 通过组合 Adaptee 来复用其接口:
// Target:客户类期望的接口
public interface Target {
void sampleOperation1();
}
// Adaptee:现有的第三方类,接口不兼容
public class Adaptee {
public void sampleOperation2() {
System.out.println("Adaptee.sampleOperation2()");
}
}
// Adapter:持有 Adaptee 引用,实现 Target
public class Adapter implements Target {
private final Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void sampleOperation1() {
adaptee.sampleOperation2();
}
}
// Client
public class Client {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new Adapter(adaptee);
target.sampleOperation1();
}
}