目录
前言
适配器模式(Adapter Pattern)是一种 结构型设计模式,用于在两个不兼容的接口之间建立桥梁,使它们可以协同工作。
它通常用于让已有的类与新接口兼容,而无需修改原有代码。
相比较于其他模式:
典型应用包括 Spring MVC HandlerAdapter
、Java I/O InputStreamReader
、AOP AdvisorAdapter
等,是一种非常常见的设计模式。
1、介绍
java的设计模式可分为:创建型模式、结构性模式、行为型模式三类。
如下图所示:
1.1、适配器模式的基本结构
1、目标接口(Target):
定义客户期望的接口。
2、被适配者(Adaptee):
需要适配的类,通常已有不兼容的方法。
3、适配器(Adapter):
连接 Target 和 Adaptee,使其兼容。
1.2、原理
可参考如下所示:
2、实现方式
适配器模式有三种主要形式:
1、对象适配器(基于组合)
2、类适配器(基于继承)
3、接口适配器(基于抽象类)
如下图所示:
java的6大原则开闭原则,可参考:
通俗讲:对于目标接口,扩展功能是开放的、修改已有功能是关闭的。
2.1、对象适配器模式
对象适配器使用 组合 方式,让适配器持有 Adaptee(被适配者)
实例,在 Adapter(适配器)
中调用 Adaptee
的方法。
示例:将 220V
电压适配为 5V
// 目标接口:手机充电器希望得到 5V 电压
interface Voltage5V {
int output5V();
}
// 被适配者:现有 220V 电压
class Voltage220V {
public int output220V() {
return 220;
}
}
// 适配器:适配 220V 到 5V
class VoltageAdapter implements Voltage5V {
private Voltage220V voltage220V; // 组合方式
public VoltageAdapter(Voltage220V voltage220V) {
this.voltage220V = voltage220V;
}
@Override
public int output5V() {
int src = voltage220V.output220V();
return src / 44; // 转换为 5V
}
}
// 客户端代码
public class AdapterPatternDemo {
public static void main(String[] args) {
Voltage220V voltage220V = new Voltage220V();
VoltageAdapter adapter = new VoltageAdapter(voltage220V);
System.out.println("输出电压:" + adapter.output5V() + "V");
}
}
优点:
- 遵循 组合优先于继承,不改变
Adaptee
的代码。 - 可以适配多个
Adaptee
,更灵活。
2.2、类适配器模式
类适配器使用 继承 方式,使
Adapter
继承Adaptee
并实现Target
接口。
// 目标接口:手机充电器希望得到 5V 电压
interface Voltage5V {
int output5V();
}
// 被适配者:现有 220V 电压
class Voltage220V {
public int output220V() {
return 220;
}
}
// 适配器:继承 Voltage220V,实现 Voltage5V
class VoltageClassAdapter extends Voltage220V implements Voltage5V {
@Override
public int output5V() {
int src = output220V(); // 直接调用父类方法
return src / 44;
}
}
缺点:
- 由于 Java 不支持多继承,适配器无法同时适配多个
Adaptee
。 - 适配器与
Adaptee
绑定,不够灵活。
2.3、接口适配器模式
基于抽类类、适用于接口中有多个方法,但客户端只需实现其中一部分的情况。
// 原始接口
interface MouseListener {
void onClick();
void onDoubleClick();
void onRightClick();
}
// 适配器:提供默认实现,子类只需实现需要的方法
abstract class MouseAdapter implements MouseListener {
@Override
public void onClick() {
}
@Override
public void onDoubleClick() {
}
@Override
public void onRightClick() {
}
}
// 只关心单击事件的子类
class ClickListener extends MouseAdapter {
@Override
public void onClick() {
System.out.println("单击事件触发");
}
}
优点:
- 让子类只需覆盖需要的方法,避免实现所有方法。
- 常用于 Java Swing、
Servlet API
的监听器适配。
3、在 Java 框架中的应用
3.1、springmvc适配器模式
具体流程如下:
Spring 定义了一个适配接口,使得每一种 Controller 有一种对应的适配器实现类。
3.2、JDBC驱动软件
数据库连接工具JDBC使得Java语言程序能够连接到数据库上,并适用SQL来查询和修改数据和数据定义。
每个数据库引擎的JDBC驱动软件都是一个介于JDBC接口和数据库引擎之间的适配器软件。
抽象的JDBC接口和各个数据库引擎的API之间都需要相应的适配器软件,即为各个数据库引擎准备的驱动软件。
3.3、Java I/O中的适配器模式
InputStreamReader和OutputStreamWriter类分别继承了Reader和Writer抽象类。但是,要创建他们的对象需要在构造器中传入一个InputStream和OutputStream的实例。
InputStreamReader和OutputStreamWriter的作用也就是将InputStream和OutputStream适配到Reader和Writer。
InputStreamReader的类结构图:
InputStreamReader实现了Reader接口,并且持有了InputStream的引用,这里是通过StreamDecoder类间接持有的,因为从byte到char要经过编码。
很显然适配器就是InputStreamReader类,而源角色就是InputStream代表的实例对象。目标接口就是Reader类。OutputStreamWriter类也是类似的方式。
4、适配器模式的优缺点
4.1、优点
解耦:让原本不兼容的类可以协同工作,而不修改原有代码。
复用:可以复用 Adaptee,减少重复代码。
扩展性强:对象适配器模式可以适配多个 Adaptee,不受继承限制。
4.2、缺点
可能增加系统复杂度:引入额外的适配器层,增加类的数量。
类适配器受限:由于 Java 不支持多继承,类适配器不能适配多个 Adaptee。
总结
对象适配器(推荐):使用 组合 方式,灵活性高,适用于大多数情况。
类适配器(局限性):使用 继承,不能适配多个 Adaptee。
接口适配器(缺省适配):适用于接口方法多,但只需要部分实现的情况。
参考文章: