使用外观模式有哪些常见误区?
简化版
外观模式常见误区包括:把 Facade 写成上帝类、把所有业务逻辑都塞进外观层、过度隐藏底层能力、接口过粗导致参数爆炸、和适配器/代理混淆。外观模式应该用于收口复杂调用,而不是替代合理的子系统设计。
详细版
常见问题:
- 一个 Facade 管全系统,类无限膨胀;
- Facade 里堆满领域规则,子系统被架空;
- 所有接口都做成粗粒度,调用方失去必要控制;
- 方法名模糊,如
process()、handle(); - 参数越来越多,内部大量 if/else;
- 把外观模式当成适配器或代理;
- 只封装表面调用,没有明确业务边界;
- Facade 相互调用形成混乱依赖;
- 远程调用聚合时忽略超时、降级和部分失败;
- 没有拆分不同业务场景的外观接口。
正确做法是按业务用例和边界拆分 Facade,让它负责流程编排和接口收口,而不是承担所有业务。
完整版教学
一、误区一:Facade 变成上帝类
最常见的问题是:
SystemFacade
createOrder()
pay()
refund()
queryUser()
exportReport()
sendMessage()
所有业务都塞进去,这不是清晰外观,而是中心化泥潭。
应该按边界拆:
OrderFacade
PaymentFacade
UserFacade
ReportFacade
二、误区二:外观层替代业务层
Facade 可以编排流程,但不应该承载所有领域规则。
不好的做法:
OrderFacade 里写价格计算、库存规则、订单状态规则、优惠券规则
更好的做法:
OrderFacade 调用 PriceService、StockService、OrderService
规则放在对应服务里,Facade 负责组织它们。
三、误区三:接口过粗
有些团队为了“统一入口”,把很多场景揉成一个方法。
结果方法参数越来越多:
process(type, flagA, flagB, mode, scene, ext)
内部大量分支,调用方也不知道该传什么。
这时应该拆成多个清晰用例接口。
四、误区四:过度隐藏底层能力
外观模式隐藏复杂性,但不是禁止所有直接访问。
有些高级调用方确实需要底层能力。
如果 Facade 只能提供很粗的接口,反而会让调用方绕路。
设计时要区分普通场景和高级场景,提供合适层级的接口。
五、误区五:微服务聚合忽略可靠性
BFF 或 Gateway 聚合多个服务时,要考虑:
- 某个服务超时怎么办;
- 是否允许部分返回;
- 是否需要降级;
- 是否要限流;
- 是否有熔断;
- 聚合接口性能是否可接受。
外观模式能简化调用,但不能自动解决分布式系统问题。
六、常见误区与追问
外观层最常见的退化是把“简化入口”写成“所有事情都归我管”。如果1个 Facade 注入15个服务、包含几十条领域判断并被所有页面调用,它已经成为难以变化的上帝类。合理做法是按用例拆分入口,让 Facade 编排流程,把不变量留给领域对象或领域服务。
| 检查维度 | 判定依据 |
|---|---|
| 合理 Facade | 薄编排、稳定用例入口 |
| 上帝 Facade | 吞并规则、依赖过多、修改频繁 |
心法:外观负责把路走顺,不负责发明每一步的业务规则。
- 误区:Facade 方法越少越好。 接口粒度应匹配用例;过粗的万能方法会带来布尔参数和隐式分支。
- 追问:如何识别它替代了领域层? 若规则只能在 Facade 内测试且领域对象只是数据容器,职责大概率越界。
- 误区:有外观后底层接口必须全部隐藏。 高级调用方仍可保留受控的细粒度入口。
- 追问:Facade 之间能互相调用吗? 偶尔复用可以,但层层互调容易形成循环依赖,应提取共同应用服务。
- 追问:怎样拆分过大的 Facade? 按业务用例或子系统边界拆分,并限制每个入口的依赖集合。
七、加强记忆
外观模式最怕从“统一入口”走向“万能入口”。正确的 Facade 应该按业务边界收口复杂调用,负责编排和聚合;不要变成上帝类,也不要替代子系统的核心职责。