← 返回题目列表

适配器模式和装饰器、代理、外观模式有什么区别?

高频 中等 第 8 / 25 题 更新于 2026/07/28
适配器模式装饰器模式代理模式外观模式设计模式对比

简化版

适配器模式关注接口转换,让不兼容接口能协作;装饰器模式关注动态增强对象功能;代理模式关注控制对象访问;外观模式关注给复杂子系统提供统一入口。适配器是“接口不合适,转一下”,装饰器是“能力不够,加一层”,代理是“访问要控制”,外观是“子系统太复杂,包一个门面”。

详细版

这几个模式都可能出现包装对象,所以容易混淆。核心区别是设计目的不同:

模式目的是否改变接口典型场景
适配器模式接口转换通常改变第三方 SDK、旧接口兼容
装饰器模式动态增强功能通常不改变Java I/O、功能叠加
代理模式控制访问通常不改变AOP、远程代理、权限控制
外观模式简化子系统调用提供更粗粒度入口统一服务门面、子系统封装

适配器强调“兼容”,装饰器强调“增强”,代理强调“控制”,外观强调“简化”。

面试时不要只看代码结构是否有包装类。很多模式结构相似,真正区分它们的是意图。

完整版教学

一、适配器模式:接口不匹配,需要转换

适配器模式的典型问题是:客户端期望一种接口,但已有类提供另一种接口。

比如系统统一接口是:

interface PayService {
    void pay(String orderId, int amount);
}

第三方 SDK 是:

class WxPayClient {
    void createTransaction(WxRequest request) {}
}

适配器负责把 pay 转换成 createTransaction

它的关键词是接口转换。

二、装饰器模式:接口合适,但想增加能力

装饰器模式中,被包装对象通常已经符合目标接口。

比如:

InputStream in = new BufferedInputStream(new FileInputStream("a.txt"));

FileInputStream 本来就是 InputStream,不需要转换接口。BufferedInputStream 的作用是增加缓冲能力。

所以装饰器的关键词是功能增强,而不是接口转换。

三、代理模式:接口合适,但访问需要控制

代理模式中,代理对象和真实对象通常实现同一个接口。

代理的目的可能是:

  • 权限校验;
  • 延迟加载;
  • 缓存;
  • 远程调用;
  • 事务控制;
  • 日志监控。

比如 Spring AOP 代理:

ServiceProxy -> RealService

客户端以为自己在调用真实服务,实际先经过代理。代理关注的是访问控制和附加处理。

四、外观模式:子系统太复杂,需要统一入口

外观模式不是为了转换某一个对象的接口,而是为了给一组复杂子系统提供简单入口。

比如:

class OrderFacade {
    void createOrder() {
        stockService.lock();
        priceService.calculate();
        couponService.freeze();
        orderService.create();
    }
}

调用方只调 OrderFacade,不用知道内部有多少子系统。

它的关键词是简化调用和隐藏复杂性。

五、从问题句式快速判断

可以用问题句式来区分:

  • 接口不兼容,但已有能力想复用:适配器;
  • 接口兼容,但想叠加功能:装饰器;
  • 接口兼容,但要控制访问:代理;
  • 子系统复杂,想提供统一入口:外观。

这个判断比背 UML 更实用。

六、它们可以组合出现

真实项目中,这些模式可能组合使用。

比如接入第三方支付:

  • 用适配器统一不同支付 SDK;
  • 用代理给支付服务加日志和熔断;
  • 用装饰器给某个支付实现叠加监控;
  • 用外观给订单系统提供统一支付入口。

多个模式同时出现不冲突,关键看每一层解决什么问题。

七、用接口是否改变和主要意图区分

旧接口 send(String) 转成 notify(Message) 是适配;同接口加重试是装饰;限制调用是代理;把 6 个子系统合成 1 个入口是外观。

adapter changes interface | decorator adds duty | proxy controls access | facade simplifies subsystem

适配器的验收标准不是“调用成功”,而是 Target 的业务语义在转换前后保持成立。参数、单位、时区、精度、空值、错误码和资源所有权都应逐项形成契约样例,否则最危险的错误会以“成功响应”的形式潜伏。

八、语义边界与契约样例验证

检查维度应确认的内容
机制正确性判断名称时先看当前对象解决的首要问题,而不是只看它持有了谁。
适用边界这些模式可叠加:Facade 内调用 Adapter,Adapter 外套重试装饰器,再由代理做鉴权。
测试证据对同一业务样例验证转换前后的单位、精度、空值和异常语义,并覆盖不可逆转换
工程代价重点统计字段映射与对象分配成本、外部模型变更影响面,以及多层版本适配造成的认知债务

易错点:判断名称时先看当前对象解决的首要问题,而不是只看它持有了谁。

九、常见误区与追问

  • 误区:外观模式和适配器都会提供新接口,所以完全相同。 外观主要简化复杂子系统,适配器主要解决既有接口与目标契约不兼容。
  • 误区:适配器只需要让方法签名能够编译。 真正的适配还包括单位、时区、错误码、空值、资源释放和幂等语义;签名一致不代表行为兼容。
  • 追问:代理能否同时转换接口? 可以承担额外职责,但若主要问题是接口转换,更准确的核心模式仍是适配器。
  • 追问:适配器应该放在哪一层? 通常放在系统边界或防腐层,让业务层只依赖 Target,避免第三方模型和异常向内扩散。
  • 追问:适配器测试为什么需要契约样例? 因为类型相同仍可能单位、精度或错误语义不同;契约样例能证明转换后的行为而不只是编译通过。

十、加强记忆

适配器、装饰器、代理、外观看起来都像“包一层”,但目的不同。适配器解决接口不兼容,装饰器解决功能增强,代理解决访问控制,外观解决子系统复杂。面试时抓住设计意图,就不会被相似结构绕进去。