外观模式有哪些角色?调用流程是什么?
简化版
外观模式主要有三个角色:Client 是调用方,Facade 是统一入口,Subsystem 是被封装的多个子系统。调用流程是 Client 调用 Facade,Facade 按业务流程调用一个或多个 Subsystem,最后把结果返回给 Client。
详细版
外观模式角色很少:
| 角色 | 作用 |
|---|---|
| Client | 使用方,只依赖外观接口 |
| Facade | 统一入口,封装复杂调用流程 |
| Subsystem | 子系统,负责具体能力 |
典型流程:
Client -> Facade -> Subsystem A
-> Subsystem B
-> Subsystem C
<- 聚合结果
Facade 不一定实现复杂算法,它主要负责组织调用顺序、适配参数、聚合结果、处理异常和控制边界。
完整版教学
一、Client:想要简单调用的一方
Client 可能是:
- Controller;
- 前端页面;
- 第三方调用方;
- 定时任务;
- 其他业务模块。
没有 Facade 时,Client 可能要依赖很多服务。
userService.check();
stockService.lock();
couponService.freeze();
orderService.create();
这会让调用方知道太多内部细节。
二、Facade:复杂流程的统一入口
Facade 对外提供更简单的方法:
class OrderFacade {
OrderResult createOrder(CreateOrderRequest request) {
// 调用多个子系统
}
}
它的职责是把复杂流程封装起来,而不是让 Client 自己拼。
三、Subsystem:真正提供能力的模块
子系统仍然负责真实业务能力。
例如:
UserService:校验用户
StockService:锁库存
CouponService:冻结优惠券
OrderService:创建订单
MessageService:发送消息
Facade 不应该把这些子系统的核心逻辑全部复制一份。它更像协调者和入口层。
四、Facade 的调用流程
一个订单外观的调用流程可能是:
1. 校验用户状态
2. 校验商品状态
3. 计算价格
4. 锁库存
5. 冻结优惠券
6. 创建订单
7. 发送订单创建事件
8. 返回订单结果
客户端看到的是一个方法:
orderFacade.createOrder(request);
这就是外观模式的价值。
五、Facade 可以有多个
大型系统里通常不会只有一个 Facade。
可以按业务能力拆分:
OrderFacade;PaymentFacade;UserFacade;AdminFacade;ReportFacade。
多个 Facade 能让边界更清晰,也避免单个类过大。
六、常见误区与追问
外观模式的角色比许多模式简单,但调用方向必须清楚。1个 Client 调用 Facade 后,Facade 可以协调3个 Subsystem;子系统仍能独立服务其他调用方,不必实现统一接口。若子系统反向调用 Facade 才能完成自身规则,层次依赖就发生了倒置。
| 检查维度 | 判定依据 |
|---|---|
| Client | 依赖高层用例入口 |
| Facade / Subsystem | 协调流程 / 提供具体能力 |
记忆钩子:调用从外到内收敛到 Facade,再由 Facade 向多个子系统展开。
- 误区:子系统必须知道 Facade 的存在。 标准结构中子系统保持独立,由 Facade 单向调用。
- 追问:一个子系统能有多个 Facade 吗? 可以按不同客户端或用例提供不同入口。
- 误区:Client 绝不能绕过 Facade。 高级功能可直接调用受控子系统接口,外观不是强制封锁层。
- 追问:Facade 能否调用另一个 Facade? 可以但应谨慎,频繁链式调用说明边界可能需要重新划分。
- 追问:流程测试关注什么? 验证调用顺序、参数转换、失败短路以及最终返回契约。
七、加强记忆
外观模式的角色很简单:Client 调外观,外观调子系统,子系统干实事。Facade 的价值是把复杂调用流程收口成一个稳定入口,让调用方少依赖内部模块。