什么是外观模式?它解决什么问题?
简化版
外观模式是给复杂子系统提供一个统一、简单的访问入口,让客户端不用直接和多个子系统交互。它主要解决调用方依赖过多、调用流程复杂、系统边界不清晰的问题。
详细版
外观模式的核心是“对外简单,对内复杂”。
例如创建订单可能涉及:
- 校验用户;
- 查询商品;
- 计算价格;
- 锁定库存;
- 冻结优惠券;
- 创建订单;
- 发送消息。
如果客户端直接调用这些服务,客户端会非常复杂。
外观模式可以提供统一入口:
class OrderFacade {
OrderResult createOrder(CreateOrderRequest request) {
userService.check(request.userId());
priceService.calculate(request);
stockService.lock(request);
couponService.freeze(request);
return orderService.create(request);
}
}
客户端只调用 OrderFacade.createOrder(),不需要知道内部有多少子系统。
完整版教学
一、外观模式为什么出现
系统越做越大,调用方经常要面对多个子系统。
比如一个后台页面要展示订单详情,可能要查:
订单服务
用户服务
商品服务
支付服务
物流服务
优惠券服务
如果每个调用方都自己组装这些信息,代码会重复,依赖会扩散,接口变化时改动面也会很大。
外观模式把这些复杂调用收口到一个统一入口。
二、外观模式的关键词是简化
外观模式不是为了增强对象能力,也不是为了控制访问,而是为了简化使用。
它做的事情通常包括:
- 聚合多个子系统;
- 隐藏复杂调用顺序;
- 提供更粗粒度接口;
- 降低客户端依赖;
- 稳定对外边界。
客户端面对的是一个简单接口,复杂性留在内部。
三、外观模式不要求屏蔽所有底层接口
外观模式不是说客户端永远不能访问子系统。
很多系统里,高级调用方可以走 Facade,底层模块之间仍然可以直接调用。
关键是:对于常见、复杂、重复的调用流程,提供一个更简单的入口。
四、外观模式和分层架构很常见
工程中很多类虽然不叫 Facade,但承担了外观职责。
例如:
OrderFacade;UserProfileFacade;ReportFacade;PaymentFacade;- BFF 层;
- API Gateway 的聚合接口;
- 应用服务层。
这些都可能是在给复杂子系统提供统一入口。
五、外观模式不是万能编排器
外观类不能无限膨胀。
如果所有业务流程都塞进一个 Facade,它会变成上帝类。
正确做法是按业务边界拆分:
OrderFacade
PaymentFacade
UserFacade
ReportFacade
外观模式追求的是边界清晰,而不是所有东西都包到一个类里。
六、常见误区与追问
外观模式解决的是子系统使用复杂度,而不是消灭子系统。客户端原本完成一次任务要按顺序调用 A、B、C 共3步,Facade 提供一个面向用例的方法并封装稳定流程;A、B、C 仍保留各自职责。这样内部重构只需调整 Facade,调用方不必同步理解细节。
| 检查维度 | 判定依据 |
|---|---|
| 没有 Facade | 客户端了解多个子系统及调用顺序 |
| 引入 Facade | 客户端依赖高层用例接口 |
记忆钩子:外观是子系统的“前台接待”,提供方便入口但不替代后台部门。
- 误区:外观模式会禁止访问子系统。 它提供可选的简化入口,不要求封闭所有细粒度接口。
- 追问:为什么它属于结构型模式? 它通过增加高层对象重新组织客户端与子系统的依赖结构。
- 误区:Facade 应包含所有业务规则。 它主要编排,核心不变量仍属于领域对象和子系统。
- 追问:外观与分层有什么关系? 分层边界常以 Facade 暴露稳定 API,但分层是更广的架构约束。
- 追问:什么时候不需要它? 子系统接口已经简单稳定且没有重复编排时,直接调用更清楚。
七、加强记忆
外观模式就是给复杂子系统包一个简单入口。它让客户端少依赖、少理解内部流程,常用于服务聚合、接口封装、分层边界和复杂流程收口。记住它的核心目的:简化使用,而不是替代所有底层设计。