facade 应暴露业务语义而非技术细节,封装高层操作、隔离子系统变更、统一异常与参数、按角色而非功能划分职责,并避免承担事务或容器耦合。

Facade 类怎么写才不算白封装
外观模式不是把一堆方法塞进一个类就完事——如果 Facade 里全是 public void doX() 且和子系统方法一一对应,那只是套壳,没降低耦合。真正有效的 Facade 应该暴露**业务语义**,而不是技术细节。
- 只暴露高层操作,比如
orderService.placeOrder(),而不是inventory.checkStock()+payment.charge()+shipping.schedule()的调用链 - 子系统类不对外暴露:把
InventoryService、PaymentGateway等设为package-private或放在独立包里,避免客户端绕过Facade直接调用 - 不要在
Facade中处理业务规则分支(如“VIP 用户跳过库存检查”)——这类逻辑应下沉到子系统内部,Facade只负责编排和转译参数
子系统接口变更时,Facade 怎么不跟着崩
子系统升级常改方法签名或抛新异常,而 Facade 如果直接透传这些变化,调用方就得跟着改。关键是在 Facade 层做一次“协议隔离”。
- 子系统返回的异常必须包装:把
InventoryException转成统一的OrderProcessingException,并保留原始异常作 cause - 参数对象别直接复用子系统 DTO:定义专属的
PlaceOrderRequest,在Facade内部做字段映射,哪怕字段名一样 - 如果子系统新增可选能力(如支持异步发货),
Facade不要立刻暴露新参数,先保持原有方法签名稳定,后续用重载或 builder 模式渐进扩展
多个 Facade 共存时,怎么避免职责混淆
一个系统里出现 OrderFacade、OrderManagementFacade、OrderQueryFacade,大概率说明边界没理清。外观模式的核心是“单一入口”,不是“多个简化版入口”。
- 按使用角色划分比按功能划分更稳妥:比如
CustomerOrderFacade(面向下单场景)和AdminOrderFacade(面向后台干预),而非按 CRUD 拆 - 共用逻辑抽成
private方法或工具类,禁止跨Facade直接调用对方的 public 方法 - 如果发现两个
Facade大量共享参数或返回类型,考虑合并,并用参数区分行为(如execute(ExecutionMode.SYNC))
Spring 里用 @Service 注解 Facade 会踩什么坑
把 Facade 声明为 Spring @Service 很自然,但容易忽略它和普通 service 的本质区别:它不承载核心业务逻辑,只协调。
立即学习“Java免费学习笔记(深入)”;
- 别给
Facade加事务注解(@Transactional)——事务边界应在子系统内部划定,Facade层加会导致超长事务、锁范围失控 - 避免在
Facade中注入ApplicationContext或调用BeanFactory,这会引入容器耦合,违背外观的“解耦”本意 - 如果子系统本身是 Spring Bean(如
PaymentService),用构造器注入;但若子系统来自外部 SDK(如 Stripe 客户端),应封装成 wrapper bean 再注入,不裸露第三方类型
Facade 最难的地方不在写法,而在判断“哪里该停手”——什么时候该把逻辑下放到子系统,什么时候该让调用方自己组合。这个分寸感,没法靠模板解决,只能靠对业务流的真实理解。










