1. 项目概述当女儿国遇上适配器模式在《Java设计模式西游篇》这个系列中作者用西游记的故事来讲解设计模式既生动又有趣。第八回讲的是适配器模式用女儿国语言无障碍这个场景来比喻适配器模式的作用非常形象。适配器模式就像是一个翻译官让讲不同语言的人能够互相交流。在女儿国的故事里唐僧师徒和女儿国的居民语言不通这时候就需要一个适配器翻译来沟通。同样在编程中当两个接口不兼容时适配器模式就能派上用场。2. 适配器模式的核心原理2.1 什么是适配器模式适配器模式(Adapter Pattern)是一种结构型设计模式它允许接口不兼容的类能够一起工作。就像电源适配器能让不同标准的插头正常工作一样在代码中适配器模式充当两个不兼容接口之间的桥梁。适配器模式主要解决接口不匹配的问题。在Java中我们经常会遇到这样的情况想使用一个类但它提供的接口与我们需要的接口不一致这时候就可以考虑使用适配器模式。2.2 适配器模式的三种形式适配器模式有三种实现方式类适配器通过继承来实现适配对象适配器通过组合来实现适配接口适配器通过抽象类来实现适配在Java中对象适配器使用得最多因为它更灵活符合组合优于继承的原则。2.3 适配器模式的UML结构适配器模式主要包含三个角色Target目标接口客户端期望的接口Adaptee被适配者需要被适配的现有接口Adapter适配器将Adaptee适配成Target3. 女儿国场景的代码实现3.1 场景设定让我们用代码来还原西游记中的场景唐僧师徒说的普通话是我们的目标接口(Target)女儿国居民说的女儿语是被适配的接口(Adaptee)我们需要一个翻译(Adapter)来让双方沟通3.2 代码实现首先定义目标接口// 目标接口普通话 public interface Mandarin { String speak(); }然后是被适配的类// 被适配者女儿语 public class DaughterLanguage { public String sayInDaughterLanguage() { return 女儿国欢迎你; // 实际女儿国语言可能是其他形式 } }接着实现适配器// 适配器翻译官 public class LanguageAdapter implements Mandarin { private DaughterLanguage daughterLanguage; public LanguageAdapter(DaughterLanguage daughterLanguage) { this.daughterLanguage daughterLanguage; } Override public String speak() { String daughterWords daughterLanguage.sayInDaughterLanguage(); // 这里进行语言转换逻辑 return translate(daughterWords); } private String translate(String daughterWords) { // 简化的翻译逻辑 if(女儿国欢迎你.equals(daughterWords)) { return 欢迎来到女儿国; } return 翻译结果; } }最后是客户端使用public class TangMonk { public static void main(String[] args) { DaughterLanguage daughterLanguage new DaughterLanguage(); Mandarin translator new LanguageAdapter(daughterLanguage); System.out.println(女儿国居民说: translator.speak()); } }4. 适配器模式的实际应用场景4.1 Java I/O中的适配器Java I/O库大量使用了适配器模式。比如InputStreamReader reader new InputStreamReader(inputStream);这里InputStreamReader就是一个适配器它将字节流InputStream适配成字符流Reader。4.2 Spring中的适配器Spring MVC中的HandlerAdapter就是典型的适配器模式应用。不同的Controller有不同的处理方式HandlerAdapter将它们统一适配成DispatcherServlet可以调用的形式。4.3 旧系统改造在系统升级改造时经常需要让新代码和旧代码协同工作。适配器模式可以很好地解决这个问题避免大规模重写旧代码。5. 适配器模式的优缺点5.1 优点可以让任何两个没有关联的类一起运行提高了类的复用性增加了类的透明度灵活性好5.2 缺点过多使用适配器会让系统变得凌乱由于Java不支持多重继承所以类适配器有一定的局限性6. 适配器模式的最佳实践6.1 何时使用适配器模式以下情况考虑使用适配器模式想使用一个已存在的类但其接口不符合需求想创建一个可复用的类该类可以与其他不相关的类协同工作想使用一些已经存在的子类但不可能对每个子类都进行适配6.2 实现注意事项对象适配器和类适配器有不同的权衡适配器模式不是为了解决还处于开发阶段的问题而是解决已有问题可以在适配器中增加一些额外的功能使适配器功能更强大7. 适配器模式与其他模式的关系7.1 适配器模式 vs 装饰器模式适配器模式改变对象的接口而装饰器模式增强对象的功能。适配器模式是为了让两个接口协同工作装饰器模式是为了给对象增加新功能。7.2 适配器模式 vs 代理模式适配器模式关注接口转换代理模式关注控制访问。代理模式通常代表一个单一对象适配器模式通常代表多个后端对象。7.3 适配器模式 vs 外观模式外观模式定义了一个新的接口而适配器模式复用一个已有的接口。适配器使两个已有接口协同工作而不是定义一个全新的接口。8. 常见面试问题8.1 适配器模式的典型应用场景面试中常被问到适配器模式的使用场景。可以回答系统需要使用现有的类但这些类的接口不符合系统的需要想要建立一个可以重复使用的类用于与一些彼此之间没有太大关联的类一起工作需要一个统一的输出接口但是输入类型不可预知8.2 适配器模式的三种实现方式区别类适配器使用继承实现只能适配一个类不需要重新实现整个被适配者对象适配器使用组合实现可以适配多个被适配者更灵活推荐使用接口适配器使用抽象类实现可以为接口提供默认实现适用于不想实现所有方法的情况8.3 适配器模式在JDK中的应用举例java.util.Arrays#asList()java.io.InputStreamReader(InputStream)java.io.OutputStreamWriter(OutputStream)javax.xml.bind.annotation.adapters.XmlAdapter9. 实际项目中的经验分享9.1 性能考虑适配器模式会引入额外的间接层可能对性能有轻微影响。在性能敏感的场景中需要权衡是否使用适配器模式。9.2 过度使用的问题适配器模式不应该被滥用。如果接口不匹配的问题很多可能需要重新设计系统架构而不是到处使用适配器。9.3 测试注意事项测试适配器时需要同时测试适配器是否正确实现了目标接口适配器是否正确调用了被适配者的方法适配器是否正确处理了各种边界情况10. 扩展思考10.1 双向适配器有时候我们需要双向适配即A可以适配BB也可以适配A。这种情况下可以实现双向适配器同时实现两个接口。10.2 适配器模式与依赖倒置原则适配器模式很好地体现了依赖倒置原则(DIP)因为它让高层模块不直接依赖低层模块而是依赖于抽象。10.3 现代Java中的适配器随着Java的发展现在有些场景可以用函数式接口或方法引用来简化适配器的实现。例如FunctionString, Integer adapter Integer::parseInt;这种写法比传统的适配器类更简洁但只适用于简单场景。