发布时间:2026/8/7 10:42:33
设计模式 09 · 适配器模式 前两篇的代理和装饰器,包装对象是为了加东西——代理加控制、装饰器加功能。这一篇的适配器模式(Adapter)也是包装,但目的完全不同:它包装一个对象,不是为了增强它,而是为了改变它的接口长相,让原本对接不上的两个东西能协作起来。一句话——适配器是个转接头。这个比喻几乎不用解释。你的笔记本是 Type-C 口,酒店墙上是国标插座,中间插一个转接头,两边就通了。转接头没给你的电脑增加任何功能,它只干一件事:把一种接口形状,转换成另一种接口形状。适配器模式在代码里干的就是这个——当你手上有一个现成的类(功能正合适),但它的方法签名/接口和你的系统要求的对不上时,你不去改它(可能也改不了,比如它是第三方库),而是写一个适配器夹在中间做转换。这一篇我们用一个特别真实的场景:对接第三方物流 API。你的系统里定义好了一套统一的物流接口,但顺丰、京东的 SDK 各有各的方法名和参数,跟你的接口完全对不上。适配器就是那个让它们能插进你系统的转接头。我们会讲清适配器的两种实现——对象适配器(靠组合)和类适配器(靠继承),以及它们的取舍;最后把适配器、装饰器、代理这三个长得很像的包装模式彻底辨析清楚,给结构型模式的包装家族做个小结。这篇文章按这条线索展开:先摆出接口对不上的具体难题;再引出适配器这个转接头的思路;然后分别实现对象适配器和类适配器,比较两者;接着看标准库和 Spring 里的真实身影;最后把三个包装模式(适配器/装饰器/代理)放在一起辨析,并给出适配器的适用边界。贯穿例是物流对接。目录一个接口对不上的难题适配器模式:夹在中间的转接头对象适配器:靠组合做转换类适配器:靠继承,以及两者的取舍现实身影:标准库与 Spring 里的适配器三个包装模式辨析:适配器 vs 装饰器 vs 代理什么时候用适配器一、一个接口对不上的难题先看场景。我们的订单系统在发货时,需要调用物流下单。为了不和具体某家快递绑死,系统里定义了一个统一的物流接口,业务代码只面向它编程:// 我方系统定义的统一物流接口publicinterfaceLogisticsService{Stringship(StringorderNo,Stringaddress);// 统一的下单方法}现在要接入顺丰。但顺丰给的 SDK 长这样——它是第三方的,你没法修改,而且方法名、参数和你的接口完全不一样:// 顺丰 SDK(第三方,不可修改)publicclassSfExpressSdk{// 方法名、参数、返回值全都和 LogisticsService 对不上publicSfResultcreateOrder(SfRequestrequest){System.out.println(顺丰下单:request);returnnewSfResult(SFSystem.currentTimeMillis());}}问题就摆在这:你的业务代码想调logisticsService.ship(orderNo, address),但顺丰只有createOrder(SfRequest)。两者功能是匹配的(都是物流下单),但接口形状对不上——方法名不同、参数结构不同、返回值不同。有人会想:那我改业务代码,直接调顺丰的createOrder不就行了?这么做有两个大问题:其一,业务代码就和顺丰焊死了,以后换京东、加菜鸟,业务代码得跟着改一遍,违反了当初定义统一接口的初衷;其二,顺丰 SDK 你根本改不了,它是个 jar 包。我们真正想要的是:让顺丰 SDK 能伪装成一个LogisticsService,插进我们的系统,而业务代码和顺丰 SDK 都不用改。中间需要一个转换层——这就是适配器。二、适配器模式:夹在中间的转接头适配器的思路直白得很:写一个新类,让它实现我方要求的接口(LogisticsService),在实现方法的内部,把调用翻译、转发给被适配的对象(顺丰 SDK)。这个夹在中间做翻译的类,就是适配器。它的三个角色:目标接口(Target):客户端期望的接口,我方的LogisticsService;被适配者(Adaptee):已存在的、接口不兼容的类,顺丰SfExpressSdk;适配器(Adapter):实现 Target 接口,内部调用 Adaptee,完成两者之间的转换。用一张图看清这个转接头夹在中间的位置:图里最关键的是那条翻译路径:客户端 → 目标接口 → 适配器(翻译)→ 被适配者。客户端始终只跟目标接口打交道,压根不知道背后是顺丰还是京东;被适配者也保持原样,不知道自己被谁包了。适配器把接口不匹配这个脏活全揽在自己身上。那么这个适配器具体怎么写?根据适配器怎么持有被适配者的方式不同,有两种实现:用组合(对象适配器)和用继承(类适配器)。我们分别看。三、对象适配器:靠组合做转换对象适配器:适配器持有一个被适配者的实例(组合),在实现目标接口方法时,调用这个实例并做参数/返回值的转换。publicclassSfLogisticsAdapterimplementsLogisticsService{privatefinalSfExpressSdksfSdk;// 组合:持有被适配者publicSfLogisticsAdapter(SfExpressSdksfSdk){this.sfSdksfSdk;}OverridepublicStringship(StringorderNo,Stringaddress){// —— 转换:把我方参数,翻译成顺丰要的格式 ——SfRequestrequestnewSfRequest();request.setBizOrderNo(orderNo);request.setReceiverAddr(address);SfResultresultsfSdk.createOrder(request);// 调用被适配者// —— 转换:把顺丰的返回,翻译成我方要的格式 ——returnresult.getWaybillNo();}}用起来,业务代码完全无感——它拿到的就是一个标准LogisticsService:LogisticsServicelogisticsnewSfLogisticsAdapter(newSfExpressSdk());Stringwaybilllogistics.ship(NO123,北京市朝阳区);// 像调自家接口一样好处很清楚:业务代码只依赖LogisticsService,顺丰 SDK 原封不动,两者的差异被SfLogisticsAdapter这个转接头彻底吸收。以后要接京东,再写一个JdLogisticsAdapter implements LogisticsService就行,业务代码一个字不改——这又是开闭原则的体现。对象适配器是实战中的首选,因为它靠组合,灵活性高:一个适配器可以适配被适配者及其子类;甚至一个适配器可以同时持有多个被适配者,把它们的能力组合起来对外提供。这也再次呼应了组合优于继承。那还有一种类适配器是干嘛的?它换用继承来实现,有它的特点,也有明显的局限。四、类适配器:靠继承,以及两者的取舍类适配器:适配器继承被适配者、同时实现目标接口。这样它自己就是一个被适配者(继承来了它的方法),又对外表现为目标接口。// 类适配器:继承被适配者 实现目标接口publicclassSfLogisticsClassAdapterextendsSfExpressSdkimplementsLogisticsService{OverridepublicStringship(StringorderNo,Stringaddress){SfRequestrequestnewSfRequest();request.setBizOrderNo(orderNo);request.setReceiverAddr(address);SfResultresultthis.createOrder(request);// 直接调用继承来的方法returnresult.getWaybillNo();}}区别就在那个this.createOrder(...)——因为继承了SfExpressSdk,适配器可以直接调用父类方法,不用再持有一个实例。但类适配器有一个 Java 特有的硬伤:Java 是单继承。适配器一旦extends SfExpressSdk,就用掉了它唯一的一次继承机会,再也没法继承别的类了。这意味着:它只能适配SfExpressSdk这一个具体类,没法像对象适配器那样灵活地适配一批相关的类;如果被适配者是final类,它连继承都做不到,类适配器直接失效。把两者对比一下:对象适配器(组合)类适配器(继承)持有被适配者的方式组合(持有实例)继承(extends)灵活性高,可适配子类、可组合多个低,只能适配一个具体类受单继承限制否是,用掉唯一继承名额能否适配 final 类能不能推荐度首选少用结论很明确:优先用对象适配器。它靠组合,更灵活、限制更少,也符合组合优于继承。类适配器只在极少数场景(比如你确实需要重写被适配者的某些方法)才考虑,大多数时候用不上。你会发现,结构型模式一路走来,组合优于继承这条原则反复地在为我们做选择——代理、装饰器、适配器,能用组合的地方,组合几乎总是更好的那个答案。五、现实身影:标准库与 Spring 里的适配器适配器在标准库里非常常见,尤其在新旧接口衔接不同体系对接的地方:InputStreamReader:这是适配器的经典案例。InputStream是字节流(一次读一个字节),Reader是字符流(一次读一个字符),两者接口不兼容。InputStreamReader就是把InputStream适配成Reader的适配器——它持有一个InputStream(对象适配器),内部按指定字符集把字节转成字符。new InputStreamReader(inputStream, UTF-8)这行你写过无数次的代码,就是在插一个字节转字符的转接头。Arrays.asList():把数组这个体系适配成List这个体系,让数组能用 List 的接口来访问。java.io里的各种XxxAdapter、Swing/AWT 的事件适配器(如MouseAdapter,给你一个空实现好让你只重写关心的方法)。Spring MVC 的HandlerAdapter:这是框架级的精彩应用。Spring MVC 支持多种风格的 Controller(注解式RequestMapping、实现Controller接口的、HttpRequestHandler的……),它们的调用方式各不相同。DispatcherServlet不可能为每种都写一套 if-else,于是引入HandlerAdapter——为每种 Controller 配一个适配器,DispatcherServlet只面向HandlerAdapter这个统一接口调用,由适配器把它翻译成对具体 Controller 的调用。这让 Spring MVC 能优雅地兼容多种 Controller 风格,是适配器统一异构接口能力的绝佳示范。一个规律:凡是你看到让一个老的/异构的/第三方的东西,能用我这套标准接口来调用的地方,背后大概率就是适配器。六、三个包装模式辨析:适配器 vs 装饰器 vs 代理到这里,结构型模式里三个长得像的包装模式——代理、装饰器、适配器——都讲完了。它们的代码骨架确实相似(都持有一个对象、都对外提供方法、都在中间做点事),极易混淆。用一张表把它们的意图彻底分开,这是结构型包装家族最该记住的一张对照:模式一句话意图接口是否改变典型信号代理控制对对象的访问不变(代理和真实对象同接口)加日志/权限/事务,你无感装饰器动态增强对象的功能不变(装饰和被装饰同接口)层层叠加新能力,你主动包适配器转换对象的接口改变(把 A 接口转成 B 接口)接口对不上,做个转接头最关键、也最好用的一条区分判据是——看接口变没变:代理和装饰器:接口不变。它们包装前后,对外的接口是同一个(都实现Order),包装是透明的,调用方用起来和原来一样,区别只在多了控制或多了功能。适配器:接口改变。它的全部使命就是把接口 A 变成接口 B,输入一种接口,输出另一种接口。接口发生转换,是适配器区别于另外两个的根本标志。再叠加上一篇那条内部对象谁给的判据,三者就彻底清晰了:接口变了 → 适配器;接口没变、你主动层层包着加功能 → 装饰器;接口没变、它替你挡在前面做管控 → 代理。结构相似是表象,意图(尤其接口变不变)才是它们各自的身份证。七、什么时候用适配器老规矩,泼冷水。适配器虽然实用,但它本质上是一种补救——它的存在,往往意味着系统里有接口不兼容的历史包袱。所以对它要有个清醒的态度。适合用适配器的信号:你想复用一个现成的类,它的功能正合适,但接口和你的系统对不上;这个类你改不了(第三方库、遗留系统、别的团队的代码),或者不该改;你需要让多个异构的实现(不同快递、不同 Controller 风格)统一到一套接口下。要警惕的信号:别把适配器当成接口设计烂的遮羞布。如果两个接口本可以一开始就设计一致,却因为随意而对不上,那正确的做法是把接口设计好,而不是事后到处贴适配器。适配器是用来对接你无法控制的外部,而不是用来给你自己能控制的内部混乱打补丁。如果一个系统里适配器满天飞,那通常是个信号:接口抽象出了问题,该回头审视设计,而不是继续加转接头。一句话:适配器是接纳既成事实的不兼容的优雅方案,但不是纵容本可避免的不兼容的借口。用它来对接外部世界,而不是掩盖内部的设计债。小结。适配器模式是个转接头:当现成的类功能合适、但接口对不上时,它夹在中间做接口转换,让两者协作,而双方都不用改。它有对象适配器(靠组合,首选)和类适配器(靠继承,受单继承所限,少用)两种实现——又一次,“组合优于继承帮我们做了选择。InputStreamReader(字节流转字符流)、Arrays.asList、Spring MVC 的HandlerAdapter,都是它的经典身影。而它和代理、装饰器最本质的区别,就一条:适配器改变接口,另外两个不改。至此,结构型的三个包装模式齐了。下一篇我们转向另一类结构型——不再是包装一个对象”,而是组织一群对象:当你面对一个树形结构(比如订单里嵌套着套餐、套餐里又嵌着子商品)时,组合模式能让你用统一的方式处理单个和一组。

相关新闻

2026/8/7 10:42:33

TechWiz LCD 3D仿真中的FFS技术应用与优化

1. 项目概述:TechWiz LCD 3D应用中的FFS仿真技术 在液晶显示(LCD)工业领域,仿真技术已经成为产品开发流程中不可或缺的一环。TechWiz作为专业的LCD光学仿真软件,其3D模块中的FFS(Fringe Field Switching,边缘场开关)仿真功能&…

2026/8/7 10:37:33

微购商城项目开发及开发流程

一、项目定位与最终成果这是一个企业级前后端分离电商平台,从截图可以看到它已经完整运行:用户(localhost:3000)——第一张截图展示的就是用户前台首页。顶部蓝色导航栏包含"首页、全部商品、购物车、登录"四个入口&…

2026/8/7 10:37:33

AI感知技术解析:从计算机视觉、语音识别到多模态融合

1. 从感官到智能:AI如何构建“看”与“听”的能力我们常说人工智能在模仿人类,而模仿的起点,往往就是我们的感官。人类通过眼睛“看”世界,通过耳朵“听”声音,大脑再将视觉、听觉乃至触觉、嗅觉等多重信息融合&#x…

2026/8/7 11:52:36

STM32 USB Host读写U盘实战:从硬件选型到稳定性调优

1. 项目缘起:为什么要在STM32上读写U盘? 几年前,我接手一个工业数据采集终端的项目,客户要求设备能定期将采集到的传感器数据导出,并且操作要足够“傻瓜”——他们希望现场工人能像在电脑上一样,直接拔插U盘…

2026/8/7 11:52:36

Unity VR医疗培训项目实战:从场景搭建到性能优化的全流程解析

1. 项目概述:从“HosptialDemo”看VR医疗培训的实战价值最近在整理过往项目时,翻到了一个名为“HosptialDemo”的Unity VR医院演示项目。这虽然只是一个演示,但麻雀虽小五脏俱全,它完整地串联起了从场景搭建、交互设计到流程模拟的…

2026/8/7 11:52:36

鸿蒙 ArkTS 实战:星座查询 Horoscope

引言 星座查询是社交、生活、娱乐类应用里十分常见的轻量工具:用户想知道自己属于哪个星座、每个星座的日期区间是什么、各自的性格特点是怎样的。本文要讲解的示例 28「星座查询 Horoscope」,用 ArkTS 在单个页面里实现了「今日星座提示 十二星座宫格 …

2026/8/7 11:47:36

无参考图像质量评估:从原理到PyTorch实战

1. 项目概述:为什么我们需要“无参考”的图像质量评估? 在图像处理、计算机视觉乃至日常的社交媒体运营中,我们每天都在和图像打交道。无论是手机拍摄的照片、网络下载的素材,还是算法生成的图片,一个绕不开的核心问题…

2026/8/5 3:13:11

如何用免费工具突破游戏窗口限制:SRWE完整使用指南

如何用免费工具突破游戏窗口限制:SRWE完整使用指南 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE 你是否遇到过这样的困扰?想为心爱的游戏截图,却发现游戏不支持自定义分辨率…

2026/8/7 0:01:55

CAD图库管理:从文件归档到设计资产管理的效率革命

你肯定遇到过这种情况:打开一个老项目,想找某个特定的图块——比如一个标准的门、一个特定的设备符号,或者一个公司logo。你记得它就在某个DWG文件里,或者曾经从某个同事那里拷来过。于是,你开始在一堆命名混乱的文件夹…

2026/8/7 0:01:55

5分钟掌握Wand-Enhancer:2026年终极WeMod专业版免费解锁指南

5分钟掌握Wand-Enhancer:2026年终极WeMod专业版免费解锁指南 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/GitHub_Trending/we/Wand-Enhancer Wand-Enhancer是一款功能强…

2026/8/7 0:01:55

“Quality Control(质量控制)”在软件工程中通常指通过一系列活动确保软件产品符合预定的质量标准和用户需求

“Quality Control(质量控制)”在软件工程中通常指通过一系列活动确保软件产品符合预定的质量标准和用户需求。而“软件测试”是质量控制的关键手段之一,属于QC范畴下的具体实践,其目标是发现缺陷、验证功能正确性、评估软件质量属…

2026/8/7 9:44:18

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/5 19:21:13

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/6 20:45:01

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…