对象适配器模式

24 阅读2分钟

该设计模式要解决什么问题?什么时候使用?

主要用于解决系统中存在需要协作的类,但它们的接口(如方法名、参数、返回值等)不匹配。 使用场景例如:

  • 系统需要使用现有的类,而这些类的接口不符合系统的需要。
  • 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作

UML类图是怎么样的

image.png

生活中的例子

第三方日志库(如Log4j)的日志输出方法为 logError(String),而你的系统要求统一调用 writeLog(LogLevel, String)。此时可以通过适配器将 logError包装成 writeLog接口

旧的用户信息类 OldUser提供 getUserName()方法,但新系统需要 fetchUsername()接口。适配器可以实现新接口,并内部调用 OldUser.getUserName()

Java中的例子

Java I/O 库中,字节流(InputStream/OutputStream)和字符流(Reader/Writer)是两种不兼容的接口。为了将字节流转换为字符流,Java 提供了 InputStreamReaderOutputStreamWriter,它们是典型的对象适配器

  • 目标接口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(); //转发调用
	}
}

优缺点

优点

  • 对于调用者而言,适配器相当于重写了被调用者的方法签名,而无需修改原来的代码
  • 通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,以适应不同接口,完全符合“开闭原则“,提高了适配者的复用性。

缺点

  • 对象适配器作为中间层,需要在适配器中封装被适配者的调用逻辑。这会增加系统的层次
  • 客户端接口变更需要修改适配器的方法,暗含耦合