资讯详情

10-A-外观模式详解

📅 2026/10/18 6:47:50 | 华诺云谱 👁 阅读
10-A-外观模式详解
10-A-外观模式详解关键词外观模式、门面、下单流程、SDK 封装、上帝类外观模式解决一个问题给复杂子系统提供一个简单的统一入口。调用方不需要知道下单背后有校验、锁库存、算价、建单、发事件五个子系统——它只调一个placeOrder()。外观是最直觉的模式也是最容易做坏的模式做成上帝类。 术语速查表术语人话解释外观Facade子系统的统一入口类把多步调用收成一个方法子系统Subsystem被封装的各个模块库存/价格/订单/事件上帝类反模式外观把所有逻辑都自己写了而不是委托门面 编排好的外观只做编排决定调用顺序和事务边界不做实现一、不用外观的问题Controller 直接调五个服务完成下单// ❌ Controller 里编排全部细节PostMapping(/order)publicResultplace(RequestBodyPlaceOrderRequestreq){// (1) 校验riskService.check(req.getUserId(),req.getSkuList());limitService.checkPurchaseLimit(req.getUserId(),req.getSkuList());// (2) 算价PriceResultpricepriceService.calculate(req.getSkuList(),req.getCouponId());// (3) 锁库存for(SkuItemitem:req.getSkuList()){inventoryService.lock(item.getSkuId(),item.getCount());}// (4) 建单OrderorderorderService.create(req.getUserId(),req.getSkuList(),price);// (5) 发事件eventPublisher.publish(newOrderCreatedEvent(order.getOrderNo()));returnResult.ok(order.getOrderNo());}痛点编排逻辑泄漏到 Controller——App、小程序、开放平台三个入口就要复制三遍步骤顺序有讲究先算价还是先锁库存散落在调用方容易写错事务边界、失败补偿没人统一管单元测试要 mock 五个服务。二、模式结构App 端小程序端开放平台OrderFacade.placeOrderRiskService风控校验PriceService算价InventoryService锁库存OrderService建单EventPublisher发事件外观只做编排决定顺序、管事务、处理失败——具体逻辑仍在各子系统里。三、业务场景下单门面ServicepublicclassOrderFacade{privatefinalRiskServiceriskService;privatefinalLimitServicelimitService;privatefinalPriceServicepriceService;privatefinalInventoryServiceinventoryService;privatefinalOrderServiceorderService;privatefinalApplicationEventPublishereventPublisher;publicOrderFacade(RiskServiceriskService,LimitServicelimitService,PriceServicepriceService,InventoryServiceinventoryService,OrderServiceorderService,ApplicationEventPublishereventPublisher){this.riskServiceriskService;this.limitServicelimitService;this.priceServicepriceService;this.inventoryServiceinventoryService;this.orderServiceorderService;this.eventPublishereventPublisher;}/** * 下单统一入口所有端都调这一个方法。 * 编排顺序是业务决策先校验(便宜) → 再算价 → 再锁库存(贵) → 建单 → 发事件 */Transactional(rollbackForException.class)publicOrderResultplaceOrder(PlaceOrderCommandcmd){// (1) 校验风控 限购失败快放最前riskService.check(cmd.getUserId(),cmd.getItems());limitService.checkPurchaseLimit(cmd.getUserId(),cmd.getItems());// (2) 算价优惠券、活动、运费PriceResultpricepriceService.calculate(cmd.getItems(),cmd.getCouponId());// (3) 锁库存最贵的操作放校验之后减少无效锁定ListLonglockednewArrayList();try{for(SkuItemitem:cmd.getItems()){inventoryService.lock(item.getSkuId(),item.getCount());locked.add(item.getSkuId());}// (4) 建单OrderorderorderService.create(cmd.getUserId(),cmd.getItems(),price);// (5) 发事件事务提交后再发用 AFTER_COMMIT 监听器见 19-A 观察者篇eventPublisher.publishEvent(newOrderCreatedEvent(order.getOrderNo()));returnOrderResult.success(order.getOrderNo());}catch(Exceptione){// 失败补偿已锁的库存要释放外观统一管理补偿调用方无感locked.forEach(skuId-inventoryService.unlock(skuId,cmd.getCount(skuId)));throwe;}}}Controller 瘦身成一行RestControllerpublicclassOrderController{privatefinalOrderFacadeorderFacade;PostMapping(/order)publicResultStringplace(RequestBodyValidPlaceOrderRequestreq){returnResult.ok(orderFacade.placeOrder(req.toCommand()).getOrderNo());}}外观带来的收益三个端复用同一套编排顺序/事务/补偿只写一遍步骤顺序这个业务决策有了唯一权威出处测试外观时 mock 子系统即可验证编排逻辑子系统内部重构如算价拆成促销运费两步不影响调用方。四、外观的三种常见形态形态例子说明服务编排门面OrderFacade收口多子系统调用顺序 事务 补偿SDK 门面支付 SDK 的PayClient.pay()把签名/加密/HTTP/重试/证书全藏起来框架门面SLF4JLoggerFactory、SpringJdbcTemplate对复杂 API 的极简包装SLF4J 是门面模式Facade 的另一种译法的命名来源应用只依赖slf4j-api底层日志实现随便换。五、框架中的同款实现框架应用说明SLF4JLogger/LoggerFactory日志门面名字就叫 FacadeSpringJdbcTemplate把 Connection/Statement/ResultSet/异常翻译收成一个 executeSpringTransactionTemplate编程式事务的门面JDKjavax.faces.context.FacesContext、URL.openStream()隐藏底层协议细节MyBatisSqlSessionselectOne/insert 门面背后是 Executor/StatementHandler 一族六、外观 vs 中介者 vs 适配器模式方向意图外观单向调用方 → 子系统简化入口子系统不知道外观存在中介者双向同事对象互相通信都经过它收敛网状交互见 17-A适配器转换接口不兼容的调和见 06-A一句话外观是我替你把复杂的都做了中介者是你们别互相打电话了都打给我。七、常见误用与生产事故误用一外观变上帝类// ❌ 外观里写了 800 行算价细节、300 行库存细节——不是编排是搬家publicclassOrderFacade{publicOrderResultplaceOrder(...){// 算价的 11 种优惠叠加逻辑全写在这里...}}判断标准外观方法的每一行应该是调用某个子系统 处理其结果一旦出现成块的业务算法就该下沉到子系统。外观的代码行数应该远小于它编排的子系统总和。误用二绕过外观直接调子系统团队定了OrderFacade统一入口但某个新需求图快直接调inventoryService.lock()跳过了风控校验——刷单团伙发现这个接口没有风控一夜锁光爆款库存。防御子系统方法收窄可见性package-private或加注解标记InternalUseOnlyArchUnit 规则Controller 不允许直接依赖 InventoryService必须经过 Facade关键校验风控/限购下沉到子系统自身做兜底——门面是便利不是唯一防线。事故门面方法上事务嵌套 RPC 导致长事务placeOrder加了Transactional其中锁库存是跨服务 RPC3s 超时。大促时库存服务抖动DB 连接被事务占住 3 秒不释放连接池耗尽整个订单库不可用。修复事务边界收缩只包住本地 DB 操作建单RPC 移出事务跨服务一致性用本地消息表 补偿替代大事务外观编排的纪律事务里不做 RPCRPC 失败靠补偿——这条写进 CR 检查单。八、总结外观的核心给复杂子系统一个简单统一的入口多端复用、编排收口。好外观只做编排顺序、事务、补偿是它的职责业务算法必须留在子系统里否则就是上帝类。门面不是唯一防线关键校验在子系统内兜底 ArchUnit 强制走门面。事务纪律门面方法的事务里不做 RPC——长事务是门面最常见的生产事故。代价外观可能变成什么都往里塞的垃圾场需要 CR 守住只编排不实现的边界。上一篇09-A-装饰器模式详解下一篇11-A-享元模式详解
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑