Java设计模式—适配器模式

适配器模式(Adapter Pattern)

适配器模式是一种结构型设计模式,用于将一个类的接口转换成客户端期望的另一个接口,使得原本不兼容的类可以协同工作。

一、模式概述

1.1 定义

适配器模式:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

1.2 适用场景

  • 想使用一个已存在的类,但其接口不符合需求
  • 需要创建一个可复用的类,与不相关或不可预见的类协同工作
  • 需要使用多个现有子类,但不可能对每个子类都进行适配

1.3 UML 类图

1
2
3
4
5
6
7
8
+----------+       +----------+       +---------+
| Client | ----> | Target | <---- | Adapter | ----> | Adaptee |
+----------+ +----------+ +---------+ +---------+
| +request()| | +request()| | +specificRequest()|
+----------+ +---------+ +---------+

类适配器:Adapter 继承 Adaptee,实现 Target
对象适配器:Adapter 持有 Adaptee 的引用,实现 Target

1.4 两种实现方式

类型实现方式优点缺点
类适配器继承 Adaptee可重写 Adaptee 方法Java 单继承限制
对象适配器组合 Adaptee更灵活,可适配多个类无法重写 Adaptee 方法

二、代码实现(类适配器)

2.1 定义 Print 接口(Target)

接口定义两个抽象方法输出字符串

1
2
3
4
public interface Print {
abstract public void PrintWeak();
abstract public void PrintStrong();
}

1.2 定义Banner类

此类定义要打印的字符串及其构造方法, 定义了两个函数打印不同的字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Banner {
private String name;

public Banner(String name) {
this.name = name;
}

public void showWithParen() {
System.out.println("(" + name + ")");
}

public void showWithAster() {
System.out.println("*" + name + "*");
}
}

1.3 定义PrintBanner类

这个类就是一个适配器,它继承了Banner类以及方法,实现了Print接口也重写了方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class PrintBanner extends Banner implements Print {

public PrintBanner(String name) {
super(name);
}

@Override
public void PrintWeak() {
showWithParen();
}

@Override
public void PrintStrong() {
showWithAster();
}
}

1.4 测试代码

这里用Print类型的变量来保存PrintBanner的实例,因为我们无需在意Banner类的方法。

1
2
3
4
5
6
7
8
9
public class RunMain {
public static void main(String[] args) {
// 编译类型为接口Print,运行类型为PrintBanner
Print print = new PrintBanner("Hello");

print.PrintStrong();
print.PrintWeak();
}
}

三、模式分析

3.1 优缺点

优点缺点
复用现有类,无需修改原有代码过多使用会使系统凌乱
增加类的透明性和灵活性类适配器受单继承限制
符合开闭原则增加系统复杂度

3.2 实际应用

  • Spring MVC 的 HandlerAdapter:适配不同类型的 Controller
  • Java I/O 中的 InputStreamReader:将 InputStream 适配为 Reader
  • JDBC 驱动:适配不同数据库的接口
1
2
3
4
5
// Java I/O 适配器示例
// InputStreamReader 将字节流适配为字符流
InputStream is = new FileInputStream("file.txt");
Reader reader = new InputStreamReader(is, "UTF-8"); // 适配器
BufferedReader br = new BufferedReader(reader);

3.3 与其他模式的区别

模式目的时机
适配器使不兼容的接口协同工作事后补救
装饰器动态添加功能设计时
代理控制对象访问设计时

四、总结

现如今,软件的更新换代很快,常常会出现新版本和旧版本的适配问题,适配器模式对于维护新版本起到了很大的作用。

设计原则:面向接口编程,而非面向实现编程。适配器模式体现了”合成复用原则”,优先使用组合而非继承。