一次重构不够,我们又推倒重来:电子面单架构的两次升级
摘要:本文完整复盘了多平台电子面单取号引擎从"能跑就行"的杂烩式大方法,到第一次策略模式雏形(已上线),再到当前流程编排+策略模式彻底解耦(含抖音接入)的两次架构升级历程。阐述了每次升级的动机、解决的问题、遗留的局限,以及最终带来的开发效率提升与线上风险降低。
📖 系列导航
- 系列开篇:从"能跑就行"到"整洁架构"
- 上一篇:数据库查询优化让多包裹取号快一倍
- 本文:两次架构升级完整复盘
- 下一篇:常量与配置集中管控改造
很多架构重构做完就结束了。但我们的电子面单引擎,重构完上线后,发现接第二个平台时又卡住了。于是有了第二次重构。
这篇文章复盘这两次升级的全过程------不只是技术选型,更是对"什么时候该重构、什么时候该停手"的思考。
文章目录
- 一次重构不够,我们又推倒重来:电子面单架构的两次升级
-
- 一、老代码时代:一个方法统治所有
-
- [1.1 代码形态](#1.1 代码形态)
- [1.2 核心痛点](#1.2 核心痛点)
- 二、第一次升级:策略模式雏形(已上线)
-
- [2.1 升级目标](#2.1 升级目标)
- [2.2 核心改动](#2.2 核心改动)
- [2.3 第一次升级后的静态结构](#2.3 第一次升级后的静态结构)
- [2.4 第一次升级的时序流程](#2.4 第一次升级的时序流程)
- [2.5 解决的问题](#2.5 解决的问题)
- [2.6 遗留的局限](#2.6 遗留的局限)
- 三、第二次升级:流程编排+策略模式彻底解耦(当前)
-
- [3.1 升级动机](#3.1 升级动机)
- [3.2 核心改动](#3.2 核心改动)
- [3.3 第一次升级 vs 第二次升级:核心差异](#3.3 第一次升级 vs 第二次升级:核心差异)
- [3.4 第二次升级后的静态结构](#3.4 第二次升级后的静态结构)
- [3.5 第二次升级后的时序流程](#3.5 第二次升级后的时序流程)
- 四、两次升级综合收益对比
- 五、当前架构全景
- 六、系列导航与参考
- [延伸阅读:Java 23种设计模式实战系列](#延伸阅读:Java 23种设计模式实战系列)
- 七、一起交流,共同进步
一、老代码时代:一个方法统治所有
1.1 代码形态
最早期的电子面单取号逻辑,全部集中在一个超过 500 行的大方法中(getQiMenWaybill)。这个方法集请求构建、API调用、响应解析、持久化、异常标记于一身。
java
// 伪代码:一个方法做了所有事
public void getWaybill(TocWmsPickTicket ticket) {
// 100+ 行:构建奇门请求
// 50+ 行:调用淘宝SDK
// 100+ 行:解析响应JSON
// 80+ 行:保存运单、绑定工作单
// 50+ 行:异常处理
}
1.2 核心痛点
- 新增平台必须改核心代码 :每接入一个平台(如从奇门扩展到抖音),都要在这个大方法中增加大量
if-else分支,代码快速膨胀。 - 一个平台改动影响所有平台:修改奇门的请求逻辑,可能误伤抖音的解析逻辑。
- 测试需要全量回归:任何一个改动,都必须测试所有已接入平台,回归成本极高。
- 配置硬编码:AppKey、Secret、Token、常量等散落各处。
- 性能隐患:包裹循环内重复查询数据库。
🏭 设计模式视角 :这种"上帝方法"是典型的违反单一职责原则(SRP) 的反面教材------一个类承担了太多职责,任何一个维度(平台、快递、流程)的变化都会导致修改,维护成本随功能增长指数级上升。在《Java 23种设计模式:从踩坑到精通》系列中,我详细拆解了六大设计原则如何指导架构演进,欢迎延伸阅读。
二、第一次升级:策略模式雏形(已上线)
2.1 升级目标
将奇门平台的取号逻辑从"大方法"中解耦出来,为后续接入新平台打下基础。
2.2 核心改动
引入"模板方法+三层策略"的雏形架构,将取号流程抽象为固定的步骤,各平台的差异通过接口实现来隔离。
2.3 第一次升级后的静态结构
下图展示了第一次升级后的类关系:虽然有了策略接口和模板编排器,但策略实现类内部仍混杂了持久化和异常标记等逻辑,策略工厂也仅使用单维度 platformCode 作为路由 Key。

2.4 第一次升级的时序流程
从动态视角看,第一次升级已经建立起了"构建→调用→判断→解析"的标准流程骨架,但各步骤内部的职责划分尚不纯净。

2.5 解决的问题
| 维度 | 改造前 | 改造后 |
|---|---|---|
| 代码组织 | 500+ 行大方法 | 模板方法 + 策略接口,职责分离 |
| 奇门维护 | 与其他平台逻辑混杂 | 独立策略实现,可单独修改 |
| 代码复用 | 无 | 模板骨架复用 |
| 测试范围 | 全量回归 | 仅需测试变更平台 |
2.6 遗留的局限
第一次升级只完成了奇门一个平台的改造,当需要接入抖音时,以下问题暴露出来:
1. 策略工厂路由仅用单一编码
StrategyFactory 使用 platformCode 作为 Map Key,导致抖音普通和代发策略互相覆盖:
java
requestMap.put("DY", new DouYinRequestStrategy()); // 普通
requestMap.put("DY", new DouYinDaiFaRequestStrategy()); // 代发(覆盖了上面)
2. 解析器混杂持久化逻辑
QiMenResponseParser 和 DouYinResponseParser 内部都包含了 commonDao.store、markTocAuditException、bindTocWorkDocAndWayBill 等非解析操作。新增平台时这些逻辑被复制粘贴,维护成本高。
3. 顺丰子母件逻辑未完全解耦
顺丰超过10件需要分批取号的逻辑,仍然部分散落在策略层,未彻底迁移到编排层。
4. 配置硬编码与常量散落
AppKey、Secret 硬编码在代码中,平台编码、上下文 Key 等魔法字符串散落各处。
三、第二次升级:流程编排+策略模式彻底解耦(当前)
3.1 升级动机
接入抖音平台时,第一次升级的局限集中爆发:策略路由覆盖、解析器越权、硬编码维护困难、常量散落导致修改遗漏。如果不彻底重构,后续接入京东、拼多多等十余个平台时,维护成本将呈指数级增长。
3.2 核心改动
1. 复合Key路由
引入 platformCode + "_" + platFormOriginal 复合 Key,与 ApiInvoker 路由规则统一。将 Key 构建方法收口到 TocWmsSourcePlatFormType.buildCompositeKey。
java
// 改造前:单维度,互相覆盖
requestMap.put("DY", new DouYinRequestStrategy());
requestMap.put("DY", new DouYinDaiFaRequestStrategy());
// 改造后:复合Key,各自独立
requestMap.put("DY_DEFAULT", new DouYinRequestStrategy());
requestMap.put("DY_DF", new DouYinDaiFaRequestStrategy());
2. 解析器职责净化
将持久化、异常标记、工作单绑定全部移出解析器,收口到 WaybillPersistence 和模板层。解析器只做纯数据转换。
3. 顺丰子母件逻辑归位
将分批取号逻辑从策略层迁移到 WaybillFetchTemplate.executeSFMoreTen 中,由编排层统一控制流程。
4. 前置校验体系
引入 LogisticsSupportable 接口,门面层在请求构建前校验平台是否支持指定快递公司。错误信息中文化,运营自助排错。
5. 性能优化
将包裹循环内的数据库查询提升到循环外一次性执行,通过 WaybillContext 透传结果。N包裹订单的查询次数从 N 降到 1。
6. 常量统一管理
将平台编码、上下文Key、快递公司编码等常量统一到 TocWmsSourcePlatFormType 和 TocWmsExpressType 中,并增加编码到中文名称的映射方法。这一部分的详细内容见下一篇《平台常量和配置管理:从散落魔法字符串到集中管控》。
3.3 第一次升级 vs 第二次升级:核心差异
| 维度 | 第一次升级(策略模式雏形) | 第二次升级(流程编排+策略解耦) |
|---|---|---|
| 策略接口 | 定义了三个接口,但实现类内部混杂了持久化、异常标记等逻辑 | 策略实现类纯粹,只做请求构建/响应解析/异常判断 |
| 解析器 | QiMenResponseParser 内部调用了 commonDao.store、markTocAuditException |
所有持久化和异常标记全部移出,解析器只做纯数据转换 |
| 工厂路由 | 单维度 platformCode 作为 Key,抖音普通和代发互相覆盖 |
复合Key platformCode + "_" + platFormOriginal,精确路由 |
| 持久化 | 散落在各解析器中,每个平台重复实现 | 统一收口到 WaybillPersistence,全平台复用 |
| 前置校验 | 无 | 引入 LogisticsSupportable 接口,门面层统一校验 |
| 子母件 | 部分逻辑散落在策略层 | 完全迁移到 WaybillFetchTemplate.executeSFMoreTen,编排层统一控制 |
| 常量管理 | 散落各处 | 统一到 TocWmsSourcePlatFormType 和 TocWmsExpressType |
| 新增平台 | 需要修改工厂 + 复制解析器中的持久化代码 | 只需新增三个纯策略类 + 注册配置 |
3.4 第二次升级后的静态结构
下图展示了第二次升级后的核心类图。与第一次升级相比,最关键的三个变化是:策略实现类不再触碰持久化 、工厂路由升级为复合Key 、子母件逻辑完全由模板层控制。

3.5 第二次升级后的时序流程
从时序图可以看到,解析器不再执行任何持久化操作,所有保存动作统一由 WaybillPersistence 在流程末端完成,异常标记也收口到了模板层的 markException 方法。

四、两次升级综合收益对比
| 维度 | 老代码 | 第一次升级 | 第二次升级 |
|---|---|---|---|
| 新增平台工作量 | 改核心代码,5-6天 | 新增3个策略类,3-4天 | 新增3个策略类+注册配置,1-2天 |
| 核心流程代码行数 | 500+行 | 约150行 | 约100行 |
| 代码复用率 | <30% | 约60% | 约85% |
| 数据库查询次数 | 包裹数×N次 | 包裹数×N次 | 1次 |
| 配置变更方式 | 改代码+重新部署 | 改代码+重新部署 | 改配置/数据库,分钟级生效 |
| 错误信息清晰度 | "系统异常" | 部分清晰 | 精确透传,自助排错 |
| 平台间影响 | 全量回归 | 工厂改动可能影响 | 完全隔离 |
| 独立部署能力 | 强耦合 | 强耦合 | 可拆分为微服务 |
五、当前架构全景

六、系列导航与参考
本篇文章是「电商多平台电子面单对接实战」的第十二篇(架构复盘篇),完整记录了电子面单取号引擎的两次架构升级历程。
系列文章目录:
- 开篇:从"能跑就行"到"整洁架构"
- 第一篇:奇门对接顺丰电子面单
- 第二篇:抖音代发电子面单对接
- 第三篇:抖音普通订单电子面单对接
- 第四篇:多平台统一架构设计
- 第五篇:策略工厂复合Key路由改造
- 第六篇:快递公司前置校验改造
- 第七篇:解析器职责分离改造
- 第八篇:模板方法的组合与继承抉择
- 第九篇:API调用调度层Handler分组设计
- 第十篇:奇门 trade_order_list 排查实录
- 第十一篇:数据库查询优化让多包裹取号快一倍
- 第十二篇:两次架构升级完整复盘(本文)
- 第十三篇:常量与配置集中管控改造
- 后续:京东、拼多多等平台专项篇
延伸阅读:Java 23种设计模式实战系列
本文中两次架构升级的核心推动力,是六大设计原则 和策略模式、模板方法模式、工厂模式的组合应用。在《Java 23种设计模式:从踩坑到精通》系列中,这些原则与模式有更体系化的拆解。如果你对以下问题感兴趣,推荐延伸阅读:
- 策略模式 vs 模板方法模式:何时用策略替换算法,何时用模板固定骨架?
- 工厂模式:简单工厂、工厂方法、抽象工厂,如何在架构演进中逐步升级?
- 六大设计原则:开闭原则、单一职责、依赖倒置......它们如何指导每一次重构决策?
📖 《Java 23 种设计模式:从踩坑到精通》
- 系列开篇:从踩坑到精通 ------ 总览与导航
- 策略模式 ------ 算法族的封装与切换
- 模板方法模式 ------ 定义算法骨架,交给子类填充细节
- 工厂模式 ------ 简单工厂→工厂方法→抽象工厂全演进
💡 学习建议 :电子面单系列侧重架构演进的真实历程 ,设计模式系列侧重理论体系与设计思维。两者搭配阅读,既能看懂一个系统如何从"能跑"进化到"可插拔",又能掌握指导每次升级的设计原则,形成"实战→理论→反哺实战"的闭环。
七、一起交流,共同进步
架构演进从来不是一蹴而就的,第一次升级为第二次升级铺了路,第二次升级为未来十余个平台扫清了障碍。如果你也在做类似的架构重构,希望这个真实的演进历程能给你一些启发。
第一次重构教会我们"怎么拆",第二次重构教会我们"怎么拆得对"。架构演进从来不是一蹴而就,而是在正确的方向上逐步逼近。
- 📌 关注我 :点击上方"关注",第一时间获取系列更新推送。
- 💬 留言讨论:您在项目中有过"第一次重构后发现不够彻底,又进行了第二次升级"的经历吗?是什么驱动了第二次升级?欢迎在评论区分享。
- 🔗 分享转发 :如果本文对您有帮助,请 点赞 、收藏 、分享,让更多同行看到。