Appearance
外观模式(Facade Pattern)
1. 官方定义
"Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use."
—— 《Design Patterns: Elements of Reusable Object-Oriented Software》(GoF, 1994)
核心:为子系统中的一组接口提供一个统一的简化入口,降低客户端与子系统的耦合。
2. 模式解释
核心思想
- 接口聚合:将多个子系统的复杂调用流程封装为简单接口(如“一键下单”功能)。
- 隐藏复杂性:客户端无需了解子系统内部细节(如订单创建 → 支付 → 物流的调用链)。
- 层级隔离:作为中间层隔离系统核心逻辑与易变的外部接口。
典型结构
plaintext
Client → Facade
△
| delegates to
|
┌───────────┴───────────┐
| | |
SubsystemA SubsystemB SubsystemC
优点
- 简化客户端:减少客户端代码量,降低学习成本。
- 解耦系统:子系统的重构或替换不影响客户端(如更换支付接口)。
- 集中控制:统一管理子系统调用顺序和异常处理。
缺点
- 过度封装风险:可能隐藏关键功能,导致定制化需求难以实现。
- 单点故障:外观类成为系统瓶颈(需结合高可用设计)。
3. 解决的问题
经典场景
- 复杂流程封装
- 电商下单流程(库存校验 → 订单生成 → 支付 → 物流通知)。
- 遗留系统整合
- 包装旧系统的分散接口为统一 API(如银行核心系统升级)。
- 跨层调用简化
- 前端通过一个 REST 接口调用多个后端微服务(BFF 模式)。
4. 实现注意事项
关键实现点
- 粒度控制
- 外观接口不宜过于臃肿(如拆分为
OrderFacade
、PaymentFacade
)。
- 外观接口不宜过于臃肿(如拆分为
- 直接访问通道
- 允许高级用户绕过外观直接访问子系统(如
Facade.getSubsystem()
)。
- 允许高级用户绕过外观直接访问子系统(如
- 异常统一处理
- 封装子系统的不同异常为客户端友好错误码。
代码示例
java
// 子系统类
class InventoryService {
public boolean checkStock(String productId) { /* ... */ }
}
class PaymentService {
public void processPayment(double amount) { /* ... */ }
}
// 外观类
class OrderFacade {
private InventoryService inventory;
private PaymentService payment;
public void placeOrder(String productId, double amount) {
if (inventory.checkStock(productId)) {
payment.processPayment(amount);
// 触发物流等其他子系统调用
}
}
}
// 客户端调用
new OrderFacade().placeOrder("P123", 99.99);
5. 实现变体
类型 | 特点 | 适用场景 |
---|---|---|
简单外观 | 直接聚合子系统调用(无抽象层) | 小型系统或临时解决方案 |
抽象外观 | 定义抽象外观接口,支持多套子系统实现(如 BasicOrderFacade / VIPOrderFacade ) | 需要动态切换子系统配置 |
6. 相似模式对比
模式 | 核心区别 |
---|---|
中介者模式 | 协调对象间交互,外观模式协调子系统间调用 |
适配器模式 | 解决接口不兼容问题,外观模式解决接口复杂性问题 |
代理模式 | 控制单个对象访问,外观模式聚合多个子系统调用 |
7. 组合使用场景
常见搭配模式
- 工厂模式
- 场景:根据配置生成不同子系统的外观(如国内/国际订单流程)。
- 单例模式
- 场景:确保全局只有一个外观实例(如系统启动器)。
- 观察者模式
- 场景:外观类触发事件通知(如订单状态变更时通知相关服务)。
总结
外观模式是复杂系统的“一键操作”按钮,其核心价值在于简化入口与隔离变化。在微服务架构中,API Gateway 是外观模式的典型实践。需注意避免创建“上帝外观”,合理拆分接口粒度,在简化性与灵活性之间找到平衡。```