该设计模式要解决什么问题?什么时候使用?
主要用于解决系统中存在需要协作的类,但它们的接口(如方法名、参数、返回值等)不匹配。 使用场景例如:
- 系统需要使用现有的类,而这些类的接口不符合系统的需要。
- 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作
UML类图是怎么样的
生活中的例子
第三方日志库(如Log4j)的日志输出方法为 logError(String),而你的系统要求统一调用 writeLog(LogLevel, String)。此时可以通过适配器将 logError包装成 writeLog接口
旧的用户信息类 OldUser提供 getUserName()方法,但新系统需要 fetchUsername()接口。适配器可以实现新接口,并内部调用 OldUser.getUserName()
Java中的例子
Java I/O 库中,字节流(InputStream/OutputStream)和字符流(Reader/Writer)是两种不兼容的接口。为了将字节流转换为字符流,Java 提供了 InputStreamReader和 OutputStreamWriter,它们是典型的对象适配器。
- 目标接口:
Reader(字符输入流)或Writer(字符输出流)。 - 被适配者:
InputStream(字节输入流)或OutputStream(字节输出流)。 - 适配器:
InputStreamReader内部持有InputStream,通过read()方法将字节转换为字符(依赖字符编码),实现Reader接口的字符读取功能。
// 将字节流(FileInputStream)适配为字符流(Reader)
InputStream inputStream = new FileInputStream("file.txt");
Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); // 适配器
int data = reader.read(); // 实际调用 InputStream 的 read(),转换为字符
关键代码
class Adapter extends Target {
private Adaptee adaptee; //维持一个对适配者对象的引用
public Adapter(Adaptee adaptee) {
this.adaptee=adaptee;
}
public void request() {
adaptee.specificRequest(); //转发调用
}
}
优缺点
优点
- 对于调用者而言,适配器相当于重写了被调用者的方法签名,而无需修改原来的代码
- 通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,以适应不同接口,完全符合“开闭原则“,提高了适配者的复用性。
缺点
- 对象适配器作为中间层,需要在适配器中封装被适配者的调用逻辑。这会增加系统的层次
- 客户端接口变更需要修改适配器的方法,暗含耦合