副标题为什么基础设施用抽象类平台差异用接口模板方法用组合「Java面试·实战笔记」系列第 2 篇上一篇我用大白话比喻帮大家彻底搞懂了接口和抽象类的基础区别没看过的朋友可以跳转第一篇【接口和抽象类有什么区别电子面单多平台对接实战】。但说实话背概念没用落地到项目才是真本事。今天这篇我直接拿线上真实落地的多平台电子面单生产架构跟大家拆解全程无虚构代码、无空洞八股文。重点讲透三个核心问题项目里的DefaultBaseManager为啥一定要用抽象类多平台差异化逻辑为啥拆成三层策略接口不用抽象类模板方法模式为啥抛弃传统继承改用组合方式实现看完这篇你以后面试被问“接口和抽象类怎么选型”再也不用死记硬背直接套生产落地逻辑回答“吊打”大部分八股文选手。文章目录副标题为什么基础设施用抽象类平台差异用接口模板方法用组合1 先复盘别停留在“背概念”要落地到“写代码”2 真实架构全景速览3 抽象类专门用来做「基础设施复用」3.1 生产真实代码DefaultBaseManager3.2 重点为啥这里必须用抽象类接口不行吗3.3 JDK源码佐证大佬也是这么写的4 接口专门用来「隔离平台业务差异」4.1 生产核心设计三层策略接口4.2 为啥这里用接口不用抽象类4.3 延伸API调度也用接口统一5 重点进阶模板方法为啥用组合不用继承5.1 传统模板方法的坑5.2 生产真实组合模板代码5.3 为啥组合比继承更香4个实战理由5.4 极简可运行Demo秒懂组合模板6 终极选型总结面试直接套7 生产踩坑真实教训避坑必看7.1 策略路由维度不足导致策略覆盖7.2 抽象类方法权限乱用7.4 传统继承模板的耦合致命坑7.3 接口default方法菱形冲突8 延伸思考新增支付宝平台该怎么改代码参考答案9 评论区面试挑战10 全文总结面试绝杀一句话 本系列完整连载阅读顺序已更新内容待更新连载1 先复盘别停留在“背概念”要落地到“写代码”上一篇我们总结了最基础的选型逻辑这里快速回顾一下抽象类代表is-a父子关系适合共享状态、通用模板、公共基础设施能力接口代表can-do能力契约适合解耦、多态、隔离业务差异之前的示例是简化版demo今天咱们直接上真实业务架构——多平台电子面单系统。这个系统要对接奇门、抖音、京东、支付宝等十几家电商平台每个平台的请求、响应、异常规则全都不一样非常适合用来讲接口、抽象类、组合模式的精准选型。2 真实架构全景速览先看精简后的分层架构图一眼看懂整体设计整个架构的核心规律一句话总结上层通用基础设施用抽象类下层平台差异化业务用接口固定流程模板用组合实现。下面逐层拆开讲每一个选型都告诉你“为什么这么写这么写的好处是什么”。3 抽象类专门用来做「基础设施复用」3.1 生产真实代码DefaultBaseManager我们项目里所有的业务Service全部统一继承DefaultBaseManager不管是订单修改服务、面单取号服务都能直接复用父类的公共能力不用每个类重复定义。publicclassTocOrderExpressModifyServiceextendsDefaultBaseManager{publicBatchResulteditTocLogistic(ListLongids,Stringexpress,StringproductCode){// 直接调用父类事务方法不用自己写事务逻辑TransactionStatusstatusbeginTxPropagationRequiresNew();// ... 业务逻辑commitTransaction(status);}}publicclassWaybillFetchServiceextendsDefaultBaseManager{publicbooleanfetchWaybill(TocWmsPickTicketticket,intexsitJianNum,StringproductCode){// 直接用父类的DAO、日志对象ctx.getExt().put(WaybillContext.KEY_COMMON_DAO,this.commonDao);logger.info(开始取号...);}}而这个抽象父类统一封装了所有业务服务的通用基础设施数据库操作对象commonDao统一日志对象logger全套事务管理方法开启事务、提交事务、回滚事务3.2 重点为啥这里必须用抽象类接口不行吗答案完全不行语法和设计层面都不支持。我给大家讲三个最核心的原因面试直接背这三点就够了① 接口不能定义实例变量无法共享状态commonDao 是需要Spring注入的实例对象每个子类都要共用。但接口里的变量默认是static final 常量根本不能定义可变的实例属性。// 编译直接报错接口做不到状态共享publicinterfaceBaseManager{CommonDaocommonDao;}② 抽象类可以写构造方法统一管理依赖注入所有子类的DAO、日志依赖都可以在抽象父类统一初始化子类直接复用不用重复注入。接口没有构造方法完全做不到。③ 语义是标准的 is-a 关系所有业务Service本质就是一个基础业务管理器完全符合抽象类的父子继承关系用继承天然合理。最终结论只要需要共享实例状态、封装通用基础设施、统一初始化依赖优先用抽象类接口替代不了。面试直接背诵3.3 JDK源码佐证大佬也是这么写的不光我们业务项目JDK底层核心源码全是这个思路AbstractList持有modCount状态字段封装集合通用逻辑AbstractMap缓存keySet、values提供Map通用骨架方法AQS抽象队列同步器持有state、head、tail核心状态是锁机制的基础父类这些核心抽象类全部都是封装通用能力、共享状态和我们的DefaultBaseManager设计思路一模一样。4 接口专门用来「隔离平台业务差异」4.1 生产核心设计三层策略接口多平台对接最大的痛点每个平台的请求、响应、异常判断逻辑全都不一样。如果写一堆if-else判断平台代码会乱到没法维护。所以我们直接抽了三层独立接口把所有平台差异彻底剥离// 1. 请求构建策略不同平台拼参规则不同publicinterfaceRequestStrategy{ObjectbuildRequest(WaybillContextctx);}// 2. 响应解析策略不同平台返回报文格式不同publicinterfaceParseStrategy{ListTocPickTicketWayBillDetailsNewparseResponse(Stringresponse,WaybillContextctx);}// 3. 异常判断策略不同平台报错字段、提示文案不同publicinterfaceExceptionStrategy{booleanisBusinessSuccess(Stringresponse);StringextractErrorMsg(Stringresponse);}然后每个平台单独实现这三套接口各自写自己的差异化逻辑// 奇门平台专属实现publicclassQiMenRequestStrategyimplementsRequestStrategy{OverridepublicObjectbuildRequest(WaybillContextctx){returnQiMenWaybillBuilder.buildRequest(ctx);}}// 抖音平台专属实现publicclassDouYinRequestStrategyimplementsRequestStrategy{OverridepublicObjectbuildRequest(WaybillContextctx){returnbuildDouYinJson(ctx);}}4.2 为啥这里用接口不用抽象类四个通俗好懂的理由① 语义是can-do能力不是is-a父子关系抖音、奇门的请求构建类不需要继承某个父类只需要具备“构建请求”的能力就行这就是接口的核心语义能力契约。② 策略类无状态不需要共享属性所有策略实现类都没有自定义成员变量所有参数都通过上下文传入无状态的业务能力用接口最轻量化。③ 支持灵活多实现扩展性拉满一个平台后续如果新增取消、重打等能力可以直接多实现多个接口抽象类只能单继承完全没这么灵活。④ 完美贴合开闭原则新增支付宝、拼多多等新平台只需要新增实现类不用改一行旧代码。如果用抽象类很容易需要修改父类逻辑破坏开闭原则。4.3 延伸API调度也用接口统一我们的API调用层同样用接口做统一约束publicinterfaceRequestHandler{Stringhandle(WaybillContextctx,Objectrequest,StringtraceId)throwsIOException;}奇门、抖音、通用HTTP、OAuth2鉴权各自实现这个接口工厂根据平台编码子渠道复合维度路由精准匹配对应处理器彻底避免策略覆盖bug。5 重点进阶模板方法为啥用组合不用继承5.1 传统模板方法的坑很多人学模板方法模式只知道用抽象类子类继承重写。但在我们的生产架构里完全抛弃了这种写法改用组合式模板 WaybillFetchTemplate。5.2 生产真实组合模板代码publicclassWaybillFetchTemplate{// 直接注入三层策略接口组合复用不用继承privatefinalRequestStrategyrequestStrategy;privatefinalParseStrategyparseStrategy;privatefinalExceptionStrategyexceptionStrategy;privatefinalApiInvokerapiInvoker;privatefinalWaybillPersistencepersistence;// 构造函数注入所有策略灵活组装publicWaybillFetchTemplate(RequestStrategyreq,ParseStrategyparse,ExceptionStrategyex,ApiInvokerinvoker,WaybillPersistencepersist){this.requestStrategyreq;this.parseStrategyparse;this.exceptionStrategyex;this.apiInvokerinvoker;this.persistencepersist;}// 固定的核心流程骨架永不修改publicbooleanexecute(WaybillContextctx){StringtraceIdctx.getTicket().getCode()_System.currentTimeMillis();try{// 1. 差异化构建请求ObjectrequestrequestStrategy.buildRequest(ctx);// 2. 通用调用APIStringresponseapiInvoker.invoke(ctx,request,traceId);// 3. 差异化业务异常判断if(!exceptionStrategy.isBusinessSuccess(response)){StringerrMsgexceptionStrategy.extractErrorMsg(response);markException(ctx.getTicket(),errMsg);returnfalse;}// 4. 差异化解析响应ListDetaildetailsparseStrategy.parseResponse(response,ctx);if(detailsnull||details.isEmpty()){markException(ctx.getTicket(),未获取到运单号);returnfalse;}// 5. 通用持久化数据booleanisFirst(ctx.getExsitJianNum()0);persistence.saveAndBind(ctx.getTicket(),details,isFirst);returntrue;}catch(Exceptione){markException(ctx.getTicket(),系统异常: e.getMessage());returnfalse;}}}5.3 为啥组合比继承更香4个实战理由① 差异逻辑已经通过接口剥离完毕没必要再继承平台的所有差异化步骤已经交给三层策略接口实现了。如果再搞一个抽象模板类让子类继承重写纯属重复造轮子代码冗余。② 彻底避免类爆炸如果用继承10个平台就要写10个模板子类。用组合一个模板类适配所有平台只需要注入不同策略即可。③ 运行时动态灵活继承的类关系编译期就固定死了组合可以在运行时通过工厂动态替换、组合策略适配不同平台、不同渠道。④ 测试极其简单可以直接Mock策略接口单独测试模板核心流程不用启动Spring容器不用依赖继承关系。⑤ 严格遵循单一职责原则代码职责高度拆分通过组合模式将「固定流程骨架」和「差异化业务逻辑」完全拆分WaybillFetchTemplate 只专注负责流程编排、通用逻辑处理、异常兜底各司其职而三层策略接口只专注各自的单一差异化能力完全贴合单一职责原则。反观传统继承式模板方法所有逻辑集中在父类和子类中极易导致模板类职责臃肿、代码耦合严重后续维护迭代成本极高。面试金句模板方法的核心是“固定流程、差异化步骤”。传统继承式适合无前置解耦的场景而我们项目中差异逻辑已通过接口独立用组合实现更轻量、更灵活、符合单一职责。5.4 极简可运行Demo秒懂组合模板下面这段代码可以直接复制运行帮你直观理解核心思想publicclassTemplateDemo{// 差异化策略接口interfaceStrategy{Stringexecute();}// 固定模板类组合策略不继承staticclassTemplate{privatefinalStrategystrategy;publicTemplate(Strategys){this.strategys;}publicvoidrun(){System.out.println(1. 公共前置步骤);System.out.println(2. strategy.execute());System.out.println(3. 公共后置步骤);}}publicstaticvoidmain(String[]args){// 平台A差异化逻辑newTemplate(()-平台A淘宝SDK签名 调用奇门API).run();// 平台B差异化逻辑newTemplate(()-平台BMD5签名 调用抖音API).run();}}运行结果1. 公共前置步骤 2. 平台A淘宝SDK签名 调用奇门API 3. 公共后置步骤 1. 公共前置步骤 2. 平台BMD5签名 调用抖音API 3. 公共后置步骤核心流程骨架固定差异化步骤可随意替换这就是组合模板的精髓。6 终极选型总结面试直接套业务场景选型方案生产案例封装DAO、日志、事务等通用基础设施抽象类DefaultBaseManager隔离各平台差异化业务逻辑接口三层策略接口统一API调用能力契约接口RequestHandler固定流程骨架步骤已通过接口解耦组合类WaybillFetchTemplate三分钟选型口诀有共享状态、通用基础设施 →抽象类无状态、纯能力契约、业务差异解耦 →接口流程固定、步骤可替换且已接口化 →组合优先于继承7 生产踩坑真实教训避坑必看7.1 策略路由维度不足导致策略覆盖早期我们只用platFormCode单维度缓存策略导致抖音普通、抖音代发策略互相覆盖requestMap.put(DY,newDouYinRequestStrategy());// 抖音普通requestMap.put(DY,newDouYinDaiFaRequestStrategy());// 直接覆盖上面的策略教训同平台多子渠道必须用platFormCode 子渠道标识复合键路由和ApiInvoker保持统一。7.2 抽象类方法权限乱用公共通用方法如果定义为protected子类可以随意重写容易绕过核心校验逻辑。规范公共固定流程用private/final保护只暴露必须实现的抽象方法。7.4 传统继承模板的耦合致命坑这也是我们彻底抛弃继承式模板方法的核心踩坑经验早期项目曾使用抽象模板类子类继承的方式实现流程编排产生了严重的继承耦合问题。一方面子类强依赖父类的实现逻辑一旦父类修改通用流程、调整参数校验规则、优化异常兜底逻辑所有继承该模板的平台子类都会被动受影响极易引发全平台隐性bug牵一发而动全身线上风险极高另一方面子类可以随意重写父类的通用固定方法部分开发不规范的重写会破坏模板预设的核心流程逻辑导致不同平台的执行流程不统一排查问题难度极大。核心教训继承是静态强耦合关系会大幅提升代码维护风险而组合是弱依赖关系通过注入策略实现能力组装完全解耦核心流程与差异化逻辑从根源规避继承耦合问题。7.3 接口default方法菱形冲突多个接口定义同名default方法实现类必须强制重写否则编译报错。开发中尽量规避同名默认方法减少冲突。8 延伸思考新增支付宝平台该怎么改代码大家可以先自己思考一下再看答案加深理解先独立思考再往下核对答案参考答案需要新增的代码零侵入旧代码支付宝请求策略ZFBRequestStrategy 实现 RequestStrategy支付宝解析策略ZFBParseStrategy 实现 ParseStrategy支付宝异常策略ZFBExceptionStrategy 实现 ExceptionStrategy支付宝API处理器ZFBHandler 实现 RequestHandler或复用通用SimpleHttpHandler需要改动的代码策略工厂注册新策略API调用器注册新处理器完全不用动的核心代码模板流程、服务层逻辑全部零改动这就是开闭原则的终极魅力新增功能只加代码不改旧逻辑。9 评论区面试挑战面试原题DefaultBaseManager用抽象类RequestStrategy用接口请从设计语义和语法限制两个角度说明选型原因标准答案设计语义DefaultBaseManager是is-a父子关系是所有服务的基础父类RequestStrategy是can-do能力契约只约束“能构建请求”的行为无继承关系。语法限制DefaultBaseManager需要持有DAO、日志等实例状态接口无法定义实例变量策略类无状态、纯行为定义接口完全适配。10 全文总结面试绝杀一句话在我们多平台电子面单架构中抽象类负责基础设施状态复用接口负责平台业务差异解耦模板方法通过组合实现灵活的流程编排三者配合完美实现了“新增平台不改动核心代码”的开闭原则。 本系列完整连载阅读顺序已更新内容第1篇《接口与抽象类到底怎么分通俗比喻基础选型框架》 上篇直达接口和抽象类有什么区别电子面单多平台对接实战内容概览用快递家族生活化比喻讲清接口、抽象类底层语义搭建基础选型判断框架通过简化面单代码区分is-a与can-do关系扫清概念层面所有八股误区。第2篇本文《从多平台电子面单架构看接口与抽象类的真实选型》内容概览基于线上电子面单生产架构落地拆解结合DefaultBaseManager抽象基类、三层策略接口、组合式模板给出可直接套用的工程选型标准附带真实踩坑与面试标准答案。 全文核心知识点速览面试极速复盘抽象类核心选型场景需共享实例状态、封装通用基础设施、统一依赖注入适配is-a父子关系不可被接口替代。接口核心选型场景无状态纯能力契约、业务差异解耦、多灵活扩展适配can-do能力关系贴合开闭原则。组合模板核心优势规避类爆炸、运行时动态适配、低耦合易测试、贴合单一职责优于传统继承模板。核心架构精髓基础设施靠抽象类复用、业务差异靠接口解耦、流程骨架靠组合灵活编排。核心避坑要点策略路由需复合维度、通用方法加权限保护、规避接口默认方法冲突、摒弃继承耦合设计。待更新连载第 3 篇《模板方法模式实战为什么组合优于继承》内容预告深挖模板方法两种实现方案对比继承耦合缺陷与组合模式的扩展性附完整可运行Demo。第 4 篇《三层策略模式拆解彻底解耦多平台差异化逻辑》内容预告拆解Request/Parse/Exception三层策略设计思路讲解策略工厂复合键路由、多平台扩展落地规范。第 5 篇《电子面单全架构复盘从踩坑到最优设计》内容预告完整复盘整套多平台电子面单链路整合抽象类、接口、策略、模板方法整套设计模式落地经验。关注专栏持续更新生产级Java面试实战内容拒绝空洞八股你在项目中有没有纠结过接口和抽象类的选型踩过哪些继承、策略路由的坑欢迎评论区交流
从多平台电子面单架构看接口与抽象类的真实选型
发布时间:2026/6/26 4:29:52
副标题为什么基础设施用抽象类平台差异用接口模板方法用组合「Java面试·实战笔记」系列第 2 篇上一篇我用大白话比喻帮大家彻底搞懂了接口和抽象类的基础区别没看过的朋友可以跳转第一篇【接口和抽象类有什么区别电子面单多平台对接实战】。但说实话背概念没用落地到项目才是真本事。今天这篇我直接拿线上真实落地的多平台电子面单生产架构跟大家拆解全程无虚构代码、无空洞八股文。重点讲透三个核心问题项目里的DefaultBaseManager为啥一定要用抽象类多平台差异化逻辑为啥拆成三层策略接口不用抽象类模板方法模式为啥抛弃传统继承改用组合方式实现看完这篇你以后面试被问“接口和抽象类怎么选型”再也不用死记硬背直接套生产落地逻辑回答“吊打”大部分八股文选手。文章目录副标题为什么基础设施用抽象类平台差异用接口模板方法用组合1 先复盘别停留在“背概念”要落地到“写代码”2 真实架构全景速览3 抽象类专门用来做「基础设施复用」3.1 生产真实代码DefaultBaseManager3.2 重点为啥这里必须用抽象类接口不行吗3.3 JDK源码佐证大佬也是这么写的4 接口专门用来「隔离平台业务差异」4.1 生产核心设计三层策略接口4.2 为啥这里用接口不用抽象类4.3 延伸API调度也用接口统一5 重点进阶模板方法为啥用组合不用继承5.1 传统模板方法的坑5.2 生产真实组合模板代码5.3 为啥组合比继承更香4个实战理由5.4 极简可运行Demo秒懂组合模板6 终极选型总结面试直接套7 生产踩坑真实教训避坑必看7.1 策略路由维度不足导致策略覆盖7.2 抽象类方法权限乱用7.4 传统继承模板的耦合致命坑7.3 接口default方法菱形冲突8 延伸思考新增支付宝平台该怎么改代码参考答案9 评论区面试挑战10 全文总结面试绝杀一句话 本系列完整连载阅读顺序已更新内容待更新连载1 先复盘别停留在“背概念”要落地到“写代码”上一篇我们总结了最基础的选型逻辑这里快速回顾一下抽象类代表is-a父子关系适合共享状态、通用模板、公共基础设施能力接口代表can-do能力契约适合解耦、多态、隔离业务差异之前的示例是简化版demo今天咱们直接上真实业务架构——多平台电子面单系统。这个系统要对接奇门、抖音、京东、支付宝等十几家电商平台每个平台的请求、响应、异常规则全都不一样非常适合用来讲接口、抽象类、组合模式的精准选型。2 真实架构全景速览先看精简后的分层架构图一眼看懂整体设计整个架构的核心规律一句话总结上层通用基础设施用抽象类下层平台差异化业务用接口固定流程模板用组合实现。下面逐层拆开讲每一个选型都告诉你“为什么这么写这么写的好处是什么”。3 抽象类专门用来做「基础设施复用」3.1 生产真实代码DefaultBaseManager我们项目里所有的业务Service全部统一继承DefaultBaseManager不管是订单修改服务、面单取号服务都能直接复用父类的公共能力不用每个类重复定义。publicclassTocOrderExpressModifyServiceextendsDefaultBaseManager{publicBatchResulteditTocLogistic(ListLongids,Stringexpress,StringproductCode){// 直接调用父类事务方法不用自己写事务逻辑TransactionStatusstatusbeginTxPropagationRequiresNew();// ... 业务逻辑commitTransaction(status);}}publicclassWaybillFetchServiceextendsDefaultBaseManager{publicbooleanfetchWaybill(TocWmsPickTicketticket,intexsitJianNum,StringproductCode){// 直接用父类的DAO、日志对象ctx.getExt().put(WaybillContext.KEY_COMMON_DAO,this.commonDao);logger.info(开始取号...);}}而这个抽象父类统一封装了所有业务服务的通用基础设施数据库操作对象commonDao统一日志对象logger全套事务管理方法开启事务、提交事务、回滚事务3.2 重点为啥这里必须用抽象类接口不行吗答案完全不行语法和设计层面都不支持。我给大家讲三个最核心的原因面试直接背这三点就够了① 接口不能定义实例变量无法共享状态commonDao 是需要Spring注入的实例对象每个子类都要共用。但接口里的变量默认是static final 常量根本不能定义可变的实例属性。// 编译直接报错接口做不到状态共享publicinterfaceBaseManager{CommonDaocommonDao;}② 抽象类可以写构造方法统一管理依赖注入所有子类的DAO、日志依赖都可以在抽象父类统一初始化子类直接复用不用重复注入。接口没有构造方法完全做不到。③ 语义是标准的 is-a 关系所有业务Service本质就是一个基础业务管理器完全符合抽象类的父子继承关系用继承天然合理。最终结论只要需要共享实例状态、封装通用基础设施、统一初始化依赖优先用抽象类接口替代不了。面试直接背诵3.3 JDK源码佐证大佬也是这么写的不光我们业务项目JDK底层核心源码全是这个思路AbstractList持有modCount状态字段封装集合通用逻辑AbstractMap缓存keySet、values提供Map通用骨架方法AQS抽象队列同步器持有state、head、tail核心状态是锁机制的基础父类这些核心抽象类全部都是封装通用能力、共享状态和我们的DefaultBaseManager设计思路一模一样。4 接口专门用来「隔离平台业务差异」4.1 生产核心设计三层策略接口多平台对接最大的痛点每个平台的请求、响应、异常判断逻辑全都不一样。如果写一堆if-else判断平台代码会乱到没法维护。所以我们直接抽了三层独立接口把所有平台差异彻底剥离// 1. 请求构建策略不同平台拼参规则不同publicinterfaceRequestStrategy{ObjectbuildRequest(WaybillContextctx);}// 2. 响应解析策略不同平台返回报文格式不同publicinterfaceParseStrategy{ListTocPickTicketWayBillDetailsNewparseResponse(Stringresponse,WaybillContextctx);}// 3. 异常判断策略不同平台报错字段、提示文案不同publicinterfaceExceptionStrategy{booleanisBusinessSuccess(Stringresponse);StringextractErrorMsg(Stringresponse);}然后每个平台单独实现这三套接口各自写自己的差异化逻辑// 奇门平台专属实现publicclassQiMenRequestStrategyimplementsRequestStrategy{OverridepublicObjectbuildRequest(WaybillContextctx){returnQiMenWaybillBuilder.buildRequest(ctx);}}// 抖音平台专属实现publicclassDouYinRequestStrategyimplementsRequestStrategy{OverridepublicObjectbuildRequest(WaybillContextctx){returnbuildDouYinJson(ctx);}}4.2 为啥这里用接口不用抽象类四个通俗好懂的理由① 语义是can-do能力不是is-a父子关系抖音、奇门的请求构建类不需要继承某个父类只需要具备“构建请求”的能力就行这就是接口的核心语义能力契约。② 策略类无状态不需要共享属性所有策略实现类都没有自定义成员变量所有参数都通过上下文传入无状态的业务能力用接口最轻量化。③ 支持灵活多实现扩展性拉满一个平台后续如果新增取消、重打等能力可以直接多实现多个接口抽象类只能单继承完全没这么灵活。④ 完美贴合开闭原则新增支付宝、拼多多等新平台只需要新增实现类不用改一行旧代码。如果用抽象类很容易需要修改父类逻辑破坏开闭原则。4.3 延伸API调度也用接口统一我们的API调用层同样用接口做统一约束publicinterfaceRequestHandler{Stringhandle(WaybillContextctx,Objectrequest,StringtraceId)throwsIOException;}奇门、抖音、通用HTTP、OAuth2鉴权各自实现这个接口工厂根据平台编码子渠道复合维度路由精准匹配对应处理器彻底避免策略覆盖bug。5 重点进阶模板方法为啥用组合不用继承5.1 传统模板方法的坑很多人学模板方法模式只知道用抽象类子类继承重写。但在我们的生产架构里完全抛弃了这种写法改用组合式模板 WaybillFetchTemplate。5.2 生产真实组合模板代码publicclassWaybillFetchTemplate{// 直接注入三层策略接口组合复用不用继承privatefinalRequestStrategyrequestStrategy;privatefinalParseStrategyparseStrategy;privatefinalExceptionStrategyexceptionStrategy;privatefinalApiInvokerapiInvoker;privatefinalWaybillPersistencepersistence;// 构造函数注入所有策略灵活组装publicWaybillFetchTemplate(RequestStrategyreq,ParseStrategyparse,ExceptionStrategyex,ApiInvokerinvoker,WaybillPersistencepersist){this.requestStrategyreq;this.parseStrategyparse;this.exceptionStrategyex;this.apiInvokerinvoker;this.persistencepersist;}// 固定的核心流程骨架永不修改publicbooleanexecute(WaybillContextctx){StringtraceIdctx.getTicket().getCode()_System.currentTimeMillis();try{// 1. 差异化构建请求ObjectrequestrequestStrategy.buildRequest(ctx);// 2. 通用调用APIStringresponseapiInvoker.invoke(ctx,request,traceId);// 3. 差异化业务异常判断if(!exceptionStrategy.isBusinessSuccess(response)){StringerrMsgexceptionStrategy.extractErrorMsg(response);markException(ctx.getTicket(),errMsg);returnfalse;}// 4. 差异化解析响应ListDetaildetailsparseStrategy.parseResponse(response,ctx);if(detailsnull||details.isEmpty()){markException(ctx.getTicket(),未获取到运单号);returnfalse;}// 5. 通用持久化数据booleanisFirst(ctx.getExsitJianNum()0);persistence.saveAndBind(ctx.getTicket(),details,isFirst);returntrue;}catch(Exceptione){markException(ctx.getTicket(),系统异常: e.getMessage());returnfalse;}}}5.3 为啥组合比继承更香4个实战理由① 差异逻辑已经通过接口剥离完毕没必要再继承平台的所有差异化步骤已经交给三层策略接口实现了。如果再搞一个抽象模板类让子类继承重写纯属重复造轮子代码冗余。② 彻底避免类爆炸如果用继承10个平台就要写10个模板子类。用组合一个模板类适配所有平台只需要注入不同策略即可。③ 运行时动态灵活继承的类关系编译期就固定死了组合可以在运行时通过工厂动态替换、组合策略适配不同平台、不同渠道。④ 测试极其简单可以直接Mock策略接口单独测试模板核心流程不用启动Spring容器不用依赖继承关系。⑤ 严格遵循单一职责原则代码职责高度拆分通过组合模式将「固定流程骨架」和「差异化业务逻辑」完全拆分WaybillFetchTemplate 只专注负责流程编排、通用逻辑处理、异常兜底各司其职而三层策略接口只专注各自的单一差异化能力完全贴合单一职责原则。反观传统继承式模板方法所有逻辑集中在父类和子类中极易导致模板类职责臃肿、代码耦合严重后续维护迭代成本极高。面试金句模板方法的核心是“固定流程、差异化步骤”。传统继承式适合无前置解耦的场景而我们项目中差异逻辑已通过接口独立用组合实现更轻量、更灵活、符合单一职责。5.4 极简可运行Demo秒懂组合模板下面这段代码可以直接复制运行帮你直观理解核心思想publicclassTemplateDemo{// 差异化策略接口interfaceStrategy{Stringexecute();}// 固定模板类组合策略不继承staticclassTemplate{privatefinalStrategystrategy;publicTemplate(Strategys){this.strategys;}publicvoidrun(){System.out.println(1. 公共前置步骤);System.out.println(2. strategy.execute());System.out.println(3. 公共后置步骤);}}publicstaticvoidmain(String[]args){// 平台A差异化逻辑newTemplate(()-平台A淘宝SDK签名 调用奇门API).run();// 平台B差异化逻辑newTemplate(()-平台BMD5签名 调用抖音API).run();}}运行结果1. 公共前置步骤 2. 平台A淘宝SDK签名 调用奇门API 3. 公共后置步骤 1. 公共前置步骤 2. 平台BMD5签名 调用抖音API 3. 公共后置步骤核心流程骨架固定差异化步骤可随意替换这就是组合模板的精髓。6 终极选型总结面试直接套业务场景选型方案生产案例封装DAO、日志、事务等通用基础设施抽象类DefaultBaseManager隔离各平台差异化业务逻辑接口三层策略接口统一API调用能力契约接口RequestHandler固定流程骨架步骤已通过接口解耦组合类WaybillFetchTemplate三分钟选型口诀有共享状态、通用基础设施 →抽象类无状态、纯能力契约、业务差异解耦 →接口流程固定、步骤可替换且已接口化 →组合优先于继承7 生产踩坑真实教训避坑必看7.1 策略路由维度不足导致策略覆盖早期我们只用platFormCode单维度缓存策略导致抖音普通、抖音代发策略互相覆盖requestMap.put(DY,newDouYinRequestStrategy());// 抖音普通requestMap.put(DY,newDouYinDaiFaRequestStrategy());// 直接覆盖上面的策略教训同平台多子渠道必须用platFormCode 子渠道标识复合键路由和ApiInvoker保持统一。7.2 抽象类方法权限乱用公共通用方法如果定义为protected子类可以随意重写容易绕过核心校验逻辑。规范公共固定流程用private/final保护只暴露必须实现的抽象方法。7.4 传统继承模板的耦合致命坑这也是我们彻底抛弃继承式模板方法的核心踩坑经验早期项目曾使用抽象模板类子类继承的方式实现流程编排产生了严重的继承耦合问题。一方面子类强依赖父类的实现逻辑一旦父类修改通用流程、调整参数校验规则、优化异常兜底逻辑所有继承该模板的平台子类都会被动受影响极易引发全平台隐性bug牵一发而动全身线上风险极高另一方面子类可以随意重写父类的通用固定方法部分开发不规范的重写会破坏模板预设的核心流程逻辑导致不同平台的执行流程不统一排查问题难度极大。核心教训继承是静态强耦合关系会大幅提升代码维护风险而组合是弱依赖关系通过注入策略实现能力组装完全解耦核心流程与差异化逻辑从根源规避继承耦合问题。7.3 接口default方法菱形冲突多个接口定义同名default方法实现类必须强制重写否则编译报错。开发中尽量规避同名默认方法减少冲突。8 延伸思考新增支付宝平台该怎么改代码大家可以先自己思考一下再看答案加深理解先独立思考再往下核对答案参考答案需要新增的代码零侵入旧代码支付宝请求策略ZFBRequestStrategy 实现 RequestStrategy支付宝解析策略ZFBParseStrategy 实现 ParseStrategy支付宝异常策略ZFBExceptionStrategy 实现 ExceptionStrategy支付宝API处理器ZFBHandler 实现 RequestHandler或复用通用SimpleHttpHandler需要改动的代码策略工厂注册新策略API调用器注册新处理器完全不用动的核心代码模板流程、服务层逻辑全部零改动这就是开闭原则的终极魅力新增功能只加代码不改旧逻辑。9 评论区面试挑战面试原题DefaultBaseManager用抽象类RequestStrategy用接口请从设计语义和语法限制两个角度说明选型原因标准答案设计语义DefaultBaseManager是is-a父子关系是所有服务的基础父类RequestStrategy是can-do能力契约只约束“能构建请求”的行为无继承关系。语法限制DefaultBaseManager需要持有DAO、日志等实例状态接口无法定义实例变量策略类无状态、纯行为定义接口完全适配。10 全文总结面试绝杀一句话在我们多平台电子面单架构中抽象类负责基础设施状态复用接口负责平台业务差异解耦模板方法通过组合实现灵活的流程编排三者配合完美实现了“新增平台不改动核心代码”的开闭原则。 本系列完整连载阅读顺序已更新内容第1篇《接口与抽象类到底怎么分通俗比喻基础选型框架》 上篇直达接口和抽象类有什么区别电子面单多平台对接实战内容概览用快递家族生活化比喻讲清接口、抽象类底层语义搭建基础选型判断框架通过简化面单代码区分is-a与can-do关系扫清概念层面所有八股误区。第2篇本文《从多平台电子面单架构看接口与抽象类的真实选型》内容概览基于线上电子面单生产架构落地拆解结合DefaultBaseManager抽象基类、三层策略接口、组合式模板给出可直接套用的工程选型标准附带真实踩坑与面试标准答案。 全文核心知识点速览面试极速复盘抽象类核心选型场景需共享实例状态、封装通用基础设施、统一依赖注入适配is-a父子关系不可被接口替代。接口核心选型场景无状态纯能力契约、业务差异解耦、多灵活扩展适配can-do能力关系贴合开闭原则。组合模板核心优势规避类爆炸、运行时动态适配、低耦合易测试、贴合单一职责优于传统继承模板。核心架构精髓基础设施靠抽象类复用、业务差异靠接口解耦、流程骨架靠组合灵活编排。核心避坑要点策略路由需复合维度、通用方法加权限保护、规避接口默认方法冲突、摒弃继承耦合设计。待更新连载第 3 篇《模板方法模式实战为什么组合优于继承》内容预告深挖模板方法两种实现方案对比继承耦合缺陷与组合模式的扩展性附完整可运行Demo。第 4 篇《三层策略模式拆解彻底解耦多平台差异化逻辑》内容预告拆解Request/Parse/Exception三层策略设计思路讲解策略工厂复合键路由、多平台扩展落地规范。第 5 篇《电子面单全架构复盘从踩坑到最优设计》内容预告完整复盘整套多平台电子面单链路整合抽象类、接口、策略、模板方法整套设计模式落地经验。关注专栏持续更新生产级Java面试实战内容拒绝空洞八股你在项目中有没有纠结过接口和抽象类的选型踩过哪些继承、策略路由的坑欢迎评论区交流