第6篇:实战案例:电子面单编排器——模板方法用继承还是组合?
2026/7/12 23:35:15 网站建设 项目流程

第6篇:实战案例:电子面单编排器——模板方法用继承还是组合?

摘要:多平台电子面单取号流程是模板方法的经典场景,但我们在真实架构中放弃了继承,选择了组合方式。本文从实战出发,对比两种实现方式的优劣,展示 WaybillFetchTemplate 如何通过注入策略对象固定流程骨架,并给出顺丰子母件分支的处理技巧。​

🔗系列导航

  • 上一篇:框架里的模板方法:HttpServlet、JdbcTemplate、AbstractList
  • 下一篇:六大设计原则在模板方法中的体现
  • 原系列总目录🔥 订阅本专栏,不错过每一篇

本文是《Java 23 种设计模式:从踩坑到精通》模板方法模式长文的扩充短文第6篇,帮助你碎片化掌握核心知识点。

前面我们用饮品制作和数据同步理解了模板方法的经典用法,但在真实的电商WMS系统中,多平台电子面单取号流程遇到了一个棘手的选择题:模板方法到底该用继承还是组合?


场景回顾:多平台取号的共性流程

电子面单取号的流程对所有平台来说都是一样的骨架:

校验订单 → 构建请求 → 调用API → 判断成功 → 解析响应 → 持久化

但每一步的具体实现因平台而异:

  • 奇门(淘宝/天猫):请求格式为XML,签名算法MD5,响应解析需遍历节点

  • 抖音:请求格式为JSON,签名算法HMAC-SHA256,响应解析需处理加密字段

  • 京东:请求格式为自定义协议,需调用京东SDK

如果每个平台都写一套完整的取号流程,代码重复不说,一旦流程变更,所有实现都要改。

我们的选择:用组合实现模板方法

传统模板方法模式用继承实现——父类定义骨架,子类覆写抽象方法。但在我们的电子面单架构中,选择了组合方式。核心编排器WaybillFetchTemplate是一个普通的类,通过构造函数注入三个策略对象:

publicclassWaybillFetchTemplate{privatefinalRequestStrategyrequestStrategy;privatefinalParseStrategyparseStrategy;privatefinalExceptionStrategyexceptionStrategy;privatefinalApiInvokerapiInvoker;privatefinalWaybillPersistencepersistence;// 通过构造函数注入策略publicWaybillFetchTemplate(RequestStrategyreq,ParseStrategyparse,ExceptionStrategyex,ApiInvokerinvoker,WaybillPersistencepersist){this.requestStrategy=req;this.parseStrategy=parse;this.exceptionStrategy=ex;this.apiInvoker=invoker;this.persistence=persist;}// 模板方法:固定取号流程骨架publicbooleanexecute(WaybillContextctx){// 1. 构建请求(策略)Objectrequest=requestStrategy.buildRequest(ctx);// 2. 调用API(统一)Stringresponse=apiInvoker.invoke(ctx,request);// 3. 业务异常判断(策略)if(!exceptionStrategy.isBusinessSuccess(response)){markException(ctx.getTicket(),exceptionStrategy.extractErrorMsg(response));returnfalse;}// 4. 解析响应(策略)List<Detail>details=parseStrategy.parseResponse(ctx,response);if(details.isEmpty()){markException(ctx.getTicket(),"未获取到运单号");returnfalse;}// 5. 持久化(统一)persistence.saveAndBind(ctx.getTicket(),details,ctx.isFirst());returntrue;}}

使用方式——运行时注入不同平台的策略:

// 奇门取号RequestStrategyreq=newQiMenRequestStrategy();ParseStrategyparse=newQiMenParseStrategy();ExceptionStrategyex=newQiMenExceptionStrategy();WaybillFetchTemplatetemplate=newWaybillFetchTemplate(req,parse,ex,invoker,persistence);template.execute(ctx);// 抖音取号req=newDouYinRequestStrategy();parse=newDouYinParseStrategy();ex=newDouYinExceptionStrategy();template=newWaybillFetchTemplate(req,parse,ex,invoker,persistence);template.execute(ctx);

为什么用组合而不是继承?

维度继承方式组合方式
类数量N 个平台 → N 个子类1 个模板类 + 3 个策略接口
灵活性编译期绑定运行时动态替换策略
测试性需创建子类实例直接 Mock 策略注入
复用性子类间无法复用策略策略可跨平台组合

关键原因:平台差异已经被三个策略接口完美隔离。如果再用一个抽象的AbstractWaybillFetchTemplate让各平台子类去实现,等于把同样的差异逻辑在两个地方重复定义——子类既要实现策略接口,又要覆写模板的抽象方法,这是典型的“过度抽象”。

模板层的额外优势:顺丰子母件分支

组合方式还有一个额外优势——在模板层增加流程分支非常自然。顺丰超过 10 件需要走子母件模式(分批调用 API),我们直接在模板类中增加一个分支方法:

publicbooleanexecute(WaybillContextctx){if(isSFMoreTen(ctx)){returnexecuteSFMoreTen(ctx);// 子母件分支:多次调用}returnexecuteNormal(ctx);// 普通分支:单次调用}

如果用继承,子母件逻辑要么重复在每个子类中实现,要么在父类中增加复杂的分支判断,很容易失控。组合方式让模板层成为唯一的流程控制点,分支逻辑清晰可维护。


一句话总结:模板方法的核心是“固定流程骨架,差异化具体步骤”。骨架既可以用继承实现,也可以用组合实现。当差异点已被策略接口隔离时,组合方式更灵活、更简洁。


📖完整长文入口:本文是模板方法模式扩充系列的第6篇。如果你想一次性阅读完整内容(含UML、完整代码、框架应用、面试追问等),请查看原长文:

👉 《Java 23 种设计模式:从踩坑到精通 | 模板方法模式》

🔗系列导航

  • 上一篇:框架里的模板方法:HttpServlet、JdbcTemplate、AbstractList
  • 下一篇:六大设计原则在模板方法中的体现
  • 返回扩充系列目录 🔥 订阅本专栏,不错过每一篇
  • 原系列总目录🔥 订阅本专栏,不错过每一篇

📖实战配套:本文的电子面单编排器设计,在《电商多平台电子面单对接实战》系列中有完整落地代码:

  • 多平台统一架构设计
  • 模板方法的组合与继承抉择

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询