策略模式:消灭优惠券 if-else,加新券就是新增一个类老代码一行不动

发布时间:2026/10/16 23:04:21

策略模式:消灭优惠券 if-else,加新券就是新增一个类老代码一行不动 作者鱼宵 「Java 后端实战精通营」设计模式系列・第 5 篇一、真实场景老板每次加一种券你就得回来加一个 else-if还记得第 1 篇那份故意写烂的外卖订单代码吗里面算优惠那段是这么写的doublefinalAmountorder.amount;if(满减.equals(order.couponType)){if(order.amount100){finalAmountorder.amount-20;}}elseif(折扣.equals(order.couponType)){finalAmountorder.amount*0.8;}当时我在第 1 篇末尾埋了个钩子这段 if-else 留着等第 5 课用策略模式收拾。今天兑现。痛点你一定熟老板下周加个无门槛券你在优惠 if 链里再补一个else if下下周加会员券又补一个。一个月后优惠方法里躺了五六个分支改满减门槛从 100 涨到 150时你得翻遍整个方法找那行 100——漏改一处线上就有人薅羊毛。这一课开药策略模式。后半节顺手讲模板方法。代码全在lesson-05clone 下来跑一遍加新券是不是真的只加一个类控制台当场演。二、核心原理把算法一个个装进小盒子随插随换2.1 策略模式是什么出门选地铁还是打车策略模式Strategy定义一族算法把它们一个个封装起来让它们可以互相替换。算法的变化被独立出来不影响用它的客户。类比出门选地铁、打车、骑车——三个是出行算法族目的地一样、算法不同随时能换。满减、折扣、无优惠就是算优惠这一族的三个算法。2.2 三个角色一句话各管什么角色本课对应类干什么抽象策略 StrategyDiscountStrategy接口定义统一入口discount(金额)具体策略 ConcreteStrategyFullReductionStrategy/PercentDiscountStrategy/NoDiscountStrategy各算各的满减、8 折、原价上下文 ContextOrderDiscountCalculator持有当前策略、对外统一入口、运行时可换面试常被追问直接new FullReductionStrategy().discount(150)不行吗行但用哪种券就写死在调用方了。上下文存在的意义就三件事持有策略 运行时切换 统一入口。用户中途换券就是setStrategy(新券)一行。2.3 错误写法 vs 正确写法摆在一起看差距// ❌ 错误写法算法挤在一个方法里加券就要回来改老代码doublecalculateBad(StringcouponType,doubleamount){if(满减.equals(couponType)){if(amount100)returnamount-20;returnamount;}elseif(折扣.equals(couponType)){returnamount*0.8;}elseif(无门槛.equals(couponType)){// 加券 改老方法returnamount-5;}returnamount;}// ✅ 正确写法每种券一个类加券 加新类老方法一行不动doublecalculateGood(DiscountStrategystrategy,doubleamount){returnstrategy.discount(amount);// 调谁由外面传进来}差别在哪错误写法里加新券是回头改一个已经上线、跑了半年的老方法——违反开闭原则OCP对扩展开放对修改关闭。正确写法里加新券是新增一个类实现DiscountStrategy老代码碰都不碰。那什么时候 if-else 反而更好分支只有两三个、几乎不会再加的地方硬上策略就是过度设计。策略买的是可维护性不是运行速度。分支会涨、算法会换才值得上策略。2.4 后半节模板方法——父类定骨架子类填空讲完策略再上一个姊妹模式。模板方法Template Method父类定好算法的骨架步骤顺序固定某些步骤的实现推迟到子类。子类不改流程结构只填细节。类比做菜。菜谱流程固定洗菜→切菜→下锅→调味放什么料由这道菜自己定。订单处理永远是这四步校验 → 算价 → 扣库存 → 通知。普通单和预售单差异只在算价和扣库存两步校验和通知完全一样。每个订单类型都把四步抄一遍改通知格式要改 N 处——这就是模板方法要干掉的重复。它有三个命门骨架方法process()必须final子类不能重写它、不能调换顺序。骨架被改了固定流程就名存实亡。抽象方法abstract父类知道要算价但不知道怎么算留空让子类填——必须实现。钩子方法Hook父类给默认实现子类可选覆盖。和抽象方法的区别抽象是必须交作业钩子是默认交了、你想改再重写。2.5 两对高频混淆题一张表背下来策略 vs 状态模式面试高频陷阱答反就挂策略是客户端主动选算法用户选了满减券平级独立状态是对象内部状态自己切自己订单从待支付变已支付行为自动变。模板方法 vs 策略模板方法策略复用手段继承子类填步骤组合换一个策略对象改流程要新写一个子类换个策略对象就行粒度一整套流程的骨架单个可互换的算法一句话模板方法用继承白箱复用策略用组合黑箱复用。三、关键代码完整可运行版含 package import 主类本课工程在lesson-05/src/main/java/com/dp/lesson05/。先看抽象策略接口——它只约定能算优惠不管怎么算packagecom.dp.lesson05;/** * 优惠策略接口策略模式的抽象策略角色。 * 把怎么算优惠抽象成一个方法每种优惠券 一个实现类。 * 策略应该无状态一个实例可被所有订单共用因为算优惠只跟入参有关。 */publicinterfaceDiscountStrategy{/** * 计算优惠后的实付金额。 * param originalAmount 订单原始金额 * return 优惠后应付金额 */doublediscount(doubleoriginalAmount);/** 策略名演示时打印出来让大家看到当前用的是哪种算法 */Stringname();}三个具体策略各算各的满减的门槛判断收在自己类内部packagecom.dp.lesson05;/** 满减策略满 100 减 20 */publicclassFullReductionStrategyimplementsDiscountStrategy{Overridepublicdoublediscount(doubleoriginalAmount){// 门槛是满减算法自己的事封在策略内部if(originalAmount100){returnoriginalAmount-20;}returnoriginalAmount;}OverridepublicStringname(){return满减券满100减20;}}packagecom.dp.lesson05;/** 折扣策略折扣率做成构造参数一个类覆盖任意折扣率 */publicclassPercentDiscountStrategyimplementsDiscountStrategy{privatefinaldoublerate;// 0.8 八折publicPercentDiscountStrategy(doublerate){this.raterate;}Overridepublicdoublediscount(doubleoriginalAmount){returnoriginalAmount*rate;}OverridepublicStringname(){return折扣券(int)(rate*10)折;}}packagecom.dp.lesson05;/** * 无优惠策略原价返回。 * 什么都不做也是一种算法显式做成策略调用方再也不用判空—— * 这就是空对象模式Null Object的味道。 */publicclassNoDiscountStrategyimplementsDiscountStrategy{Overridepublicdoublediscount(doubleoriginalAmount){returnoriginalAmount;}OverridepublicStringname(){return无优惠原价;}}接下来是上下文——三行核心持有策略、可切换、委托packagecom.dp.lesson05;/** * 优惠计算器上下文 Context。 * 持有当前策略真正算钱的活儿委托给策略去做自己只做编排。 */publicclassOrderDiscountCalculator{privateDiscountStrategystrategy;// 当前生效的策略publicOrderDiscountCalculator(DiscountStrategystrategy){this.strategystrategy;}/** 运行时切换策略电商里用户换了一张券就是这一行 */publicvoidsetStrategy(DiscountStrategystrategy){this.strategystrategy;System.out.println( [计算器] 切换优惠策略 - strategy.name());}/** 统一入口把活儿全部委托给当前策略自己不算钱 */publicdoublecalculate(doubleoriginalAmount){returnstrategy.discount(originalAmount);}publicStringcurrentStrategyName(){returnstrategy.name();}}模板方法部分。父类把四步骨架用final锁死两个抽象步骤留空通知是钩子packagecom.dp.lesson05;/** * 订单处理流程模板模板方法的抽象类角色。 * 骨架校验 - 算价 - 扣库存 - 通知顺序由 final 锁死。 */publicabstractclassAbstractOrderProcessTemplate{/** 骨架方法final 锁死子类不能改流程顺序 */publicfinalvoidprocess(Orderorder){validate(order);// 步骤1通用父类实现doublepricecalcPrice(order);// 步骤2抽象子类填deductStock(order);// 步骤3抽象子类填notify(order,price);// 步骤4钩子父类给默认}/** 步骤1所有订单通用的校验写死在父类 */protectedvoidvalidate(Orderorder){if(order.getOrderId()null||order.getOrderId().isEmpty()){thrownewIllegalArgumentException(订单号不能为空);}System.out.println( [流程] 校验通过订单 order.getOrderId());}/** 步骤2抽象方法子类必须实现 */protectedabstractdoublecalcPrice(Orderorder);/** 步骤3抽象方法子类必须实现 */protectedabstractvoiddeductStock(Orderorder);/** * 步骤4钩子方法Hook。 * 不是 abstract父类给了默认实现子类想改才重写。 * 分清 abstract 还是 Hook 的口诀子类不改行不行行 钩子。 */protectedvoidnotify(Orderorder,doubleprice){System.out.println(String.format( [流程] 通知用户订单 %s 实付 %.2f 元,order.getOrderId(),price));}}两个子类只填差异。普通单算价走策略计算器这里是模板方法 策略两个模式配合预售单算活动价packagecom.dp.lesson05;/** 普通单算价走策略计算器扣库存立即扣 */publicclassNormalOrderProcessextendsAbstractOrderProcessTemplate{privatefinalOrderDiscountCalculatorcalculator;publicNormalOrderProcess(OrderDiscountCalculatorcalculator){this.calculatorcalculator;}OverrideprotecteddoublecalcPrice(Orderorder){doublepricecalculator.calculate(order.getAmount());System.out.println(String.format( [流程] 普通单算价原价 %.2f - 实付 %.2f%s,order.getAmount(),price,calculator.currentStrategyName()));returnprice;}OverrideprotectedvoiddeductStock(Orderorder){System.out.println( [流程] 普通单立即扣减库存);}// notify 没重写吃父类默认实现这就是钩子可选覆盖的演示}packagecom.dp.lesson05;/** 预售单算活动价不用券只锁库存不扣 */publicclassPresaleOrderProcessextendsAbstractOrderProcessTemplate{OverrideprotecteddoublecalcPrice(Orderorder){doublepriceorder.getAmount()*0.9;// 预售 9 折System.out.println(String.format( [流程] 预售单算价活动价 %.2f原价 %.2f不用券,price,order.getAmount()));returnprice;}OverrideprotectedvoiddeductStock(Orderorder){System.out.println( [流程] 预售单只锁库存不扣减发货日才扣);}}最后是入口 Main把策略切换和模板流程各跑一遍packagecom.dp.lesson05;publicclassMain{publicstaticvoidmain(String[]args){System.out.println( 第 5 课策略模式——优惠计算 if-else 的末日 );// 1. 初始策略 无优惠没券就是没券不用 if 判断OrderDiscountCalculatorcalculatornewOrderDiscountCalculator(newNoDiscountStrategy());payOnce(calculator,150);payOnce(calculator,88);// 2. 用户换了满减券运行时切换订单服务一行不改calculator.setStrategy(newFullReductionStrategy());payOnce(calculator,150);// 满100减20payOnce(calculator,80);// 不满100不减// 3. 又换成 8 折券calculator.setStrategy(newPercentDiscountStrategy(0.8));payOnce(calculator,88);System.out.println();System.out.println( 第 5 课模板方法——订单处理流程骨架 );// 4. 普通单流程四步骨架跑一遍此刻计算器里装的是 8 折策略OrdernormalnewOrder(A2001,NORMAL,150);AbstractOrderProcessTemplatenormalProcessnewNormalOrderProcess(calculator);System.out.println(-- 跑普通单流程 --);normalProcess.process(normal);System.out.println();// 5. 预售单流程四步顺序一模一样算价/扣库存做法完全不同OrderpresalenewOrder(A2002,PRESALE,200);AbstractOrderProcessTemplatepresaleProcessnewPresaleOrderProcess();System.out.println(-- 跑预售单流程 --);presaleProcess.process(presale);System.out.println();System.out.println( 结束加新券新增策略类新订单类型新增子类老代码一行不动 );}/** 小工具按当前策略算一单并打印 */privatestaticvoidpayOnce(OrderDiscountCalculatorcalculator,doubleamount){doublepaycalculator.calculate(amount);System.out.println(String.format( 金额 %.2f 用[%s] - 实付 %.2f,amount,calculator.currentStrategyName(),pay));}}这段代码讲了什么前半段同一个计算器被中途换了三次策略无优惠→满减→8 折调用方一行没改后半段普通单和预售单严格走四步差异只在算价和扣库存。四、完整演示 实测输出clone 下来后在lesson-05目录执行Windows PowerShellcd C:\Users\haoji\Desktop\课程\design-patterns-journey\lesson-05$env:JAVA_HOMEC:\jdk\jdk-17.0.12mvn clean install-DskipTests看到BUILD SUCCESS后运行中文乱码先设 936 编码[Console]::OutputEncoding[System.Text.Encoding]::GetEncoding(936)C:\jdk\jdk-17.0.12\bin\java.exe-cp.\target\classescom.dp.lesson05.Main实测输出 第 5 课策略模式——优惠计算 if-else 的末日 金额 150.00 用[无优惠原价] - 实付 150.00 金额 88.00 用[无优惠原价] - 实付 88.00 [计算器] 切换优惠策略 - 满减券满100减20 金额 150.00 用[满减券满100减20] - 实付 130.00 金额 80.00 用[满减券满100减20] - 实付 80.00 [计算器] 切换优惠策略 - 折扣券8折 金额 88.00 用[折扣券8折] - 实付 70.40 第 5 课模板方法——订单处理流程骨架 -- 跑普通单流程 -- [流程] 校验通过订单 A2001 [流程] 普通单算价原价 150.00 - 实付 120.00折扣券8折 [流程] 普通单立即扣减库存 [流程] 通知用户订单 A2001 实付 120.00 元 -- 跑预售单流程 -- [流程] 校验通过订单 A2002 [流程] 预售单算价活动价 180.00原价 200.00不用券 [流程] 预售单只锁库存不扣减发货日才扣 [流程] 通知用户订单 A2002 实付 180.00 元 结束加新券新增策略类新订单类型新增子类老代码一行不动 输出解读三个细节前半段策略同一个计算器先无优惠150→150切满减150→130、80→80 不满门槛再切 8 折88→70.4——算法在运行中途被换掉调用方一行没改。后半段模板方法普通单和预售单严格走四步差异只在算价和扣库存两行。普通单那行括号里是折扣券8折因为计算器里此刻装的还是 8 折策略——模板方法的算价步骤内部又委托给了策略。五、挑战题改参数会怎样答案在源码里⭐ 把Main里new PercentDiscountStrategy(0.8)改成(0.7)再跑一遍——88 那单实付多少注意name()里那行(int)(rate*10)打印是7折还是8折⭐⭐ 把AbstractOrderProcessTemplate.process()的final去掉让PresaleOrderProcess重写一个process()故意把顺序倒过来先通知再算价——编译报不报错跑出来和父类流程差在哪⭐⭐ 给抽象模板加钩子protected boolean needNotify() { return true; }在notify()开头加if (!needNotify()) return;让PresaleOrderProcess覆盖它返回false——重跑预售单最后那行通知用户还在不在三题改完跑一遍现象都在lesson-05源码里。跑出来和你想的不一样评论区贴出来。六、生产环境进阶Spring 里你天天用只是没意识到手写一个接口 三个实现 一个上下文是为了看清本质。真实项目里这两个模式早就被框架包好了1. Spring 注入MapString, DiscountStrategy——生产最常用的策略分发ServicepublicclassCouponService{// Spring 自动把所有 DiscountStrategy 类型的 Bean 按名字灌进来AutowiredprivateMapString,DiscountStrategystrategyMap;publicdoublepay(StringcouponType,doubleamount){// 加新券 新写一个 Bean 实现接口这里一行 if 都不用加returnstrategyMap.get(couponType).discount(amount);}}你写过的Autowired MapString, SomeStrategy就是策略的 Spring 落地——框架帮你把接口→多实现→按名取全干了。2. JDK 里你已经用过几百次策略——Comparator和拒绝策略ListOrderorders...;orders.sort((a,b)-Double.compare(b.getAmount(),a.getAmount()));// lambda 就是排序策略newThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,newLinkedBlockingQueue(100),newThreadPoolExecutor.CallerRunsPolicy());// 拒绝策略Comparator是策略接口JDK 的sort()是固定算法怎么比由你传的 lambda 决定。RejectedExecutionHandler四个内置实现AbortPolicy 抛异常、CallerRunsPolicy 调用者跑、DiscardPolicy 丢、DiscardOldestPolicy 丢最老的也是策略。3. 模板方法的天花板——Spring 的JdbcTemplate它把拿连接 → 建 Statement → 执行 SQL → 关资源 → 异常翻译这套固定流程全锁在父类里你只写 SQL 那段。拿连接、关资源、把SQLException翻译成DataAccessException——这些脏活全是固定的是父类骨架action.doInStatement(stmt)是你写的 SQL是子类填的步骤。你用 JdbcTemplate 时传的那个 lambda就是模板方法里留空的那一步。## 七、面试回答模板Q1策略模式怎么消灭 if-else为什么说新增优惠券 新增一个类一句话结论把分支搬进多态——每种算法封装成一个实现类上下文持有策略并委托新增行为 新增实现类不改老代码。展开坏代码里if (满减) / else if (折扣)把三种算法挤在一个方法里策略模式把每个分支抽成DiscountStrategy的一个实现加无门槛券就是新写一个类老代码一行不动这就是开闭原则。指向本文第二节。Q2策略模式里 Context 是干什么的一句话结论上下文 策略的持有者 请求的转发者它自己不算算法只做编排。展开上下文三个价值——持有当前策略、统一入口calculate()、运行时setStrategy()切换电商里用户中途换券就是这一行。指向本文第三节。Q3模板方法和策略模式什么区别Spring 里哪里是这俩一句话结论模板方法用继承白箱、父类定骨架子类填步骤策略用组合黑箱、换个策略对象就行。展开JdbcTemplate / RestTemplate 是模板方法MapString, XxxStrategy注入、Comparator、拒绝策略是策略。指向本文第二、六节。八、总结表坑原因解法加一种优惠券就要回来加else if算法挤在一个方法里违反开闭原则每种券 一个策略类上下文持有切换本文第二节直接在调用方new FullReductionStrategy()用哪种券写死丢了运行时切换能力加一层 ContextsetStrategy()运行时换模板方法骨架忘了加final编译不报错但子类重写process()把流程打乱骨架方法必须final这是命门把可选步骤声明成abstract每个子类被迫实现一堆用不到的方法分不清 abstract 还是 Hook 就问子类不改行不行行 钩子九、关于这个系列本文是「Java 后端实战精通营」设计模式系列第 5 篇。这个系列不按 23 种模式教科书式罗列只打三张牌面试高频模式 Spring/JDK 源码真实落点 第 1 篇那份外卖烂代码逐节开药。完整可运行工程https://gitee.com/j67mk2/design-patterns本课源码在lesson-05/主类com.dp.lesson05.Main下一篇预告《观察者模式下单成功订单服务一个 if 都不加所有关心它的模块自动收到消息》。第 1 篇里发通知的三个ifneedSms / needEmail / needAppPush就是下一课手术对象——手写一个极简事件总线下单成功发布事件短信、邮件、App 推送各自订阅加微信通知 新增一个监听器。互动提问你项目里有没有一段加一种分支就要回来改老方法的代码是优惠券支付渠道通知方式评论区说说我帮你判断该上策略、观察者还是责任链。本文部分内容由 AI 辅助生成
延伸阅读

更多相关文章

2026/10/16 22:59:19

从天才猜想到生成式AI:一文看懂人工智能70年发展史

2022年冬天,一款对话式AI助手在短短两个月里冲上亿级用户,连家里长辈都在问“这东西怎么突然就冒出来了”。很多人觉得AI是这两年才火起来的新鲜事,实际上,从“机器能不能思考”这个天才猜想被正式提出算起,AI已经走了…

2026/10/16 22:59:19

深度学习新手入门评估指南:GPU环境、训练调试与工程实践

很多刚接触深度学习的新手都会有这样一个状态:视频课看完了,教程跟跑了,模型也训练过一次,但一旦有人拿出一套正式的评估题目,心里就没底。这个现象在NVIDIA深度学习新手入门Assessment里特别明显——它设计的初衷就是…

2026/10/16 22:59:19

SSD先验框8732的生成原理与工程调优指南

1. 项目概述:为什么8732这个数字在SSD里像“出厂设置”一样牢不可破?你打开任何一份SSD(Single Shot MultiBox Detector)的源码,只要它没被魔改过,几乎必然会在prior_box.py或类似配置文件里看到一行硬编码…

2026/10/17 2:54:45

模仿学习三大范式:BC、IRL与GAIL落地实战指南

简介:本资源是一套面向深度强化学习研究者与进阶开发者的模仿学习算法开源实现,聚焦于在PPO策略框架下对比分析主流逆强化学习与行为克隆方法。涵盖AIRL、BC、DRIL、FAIRL、GAIL、GMMIL、nn-PUGAIL、RED等8种核心算法,并支持状态-only模仿、吸…

2026/10/17 2:54:45

龙勃透镜反射器原理与Matlab仿真:从射线追踪到RCS预估

做外场试验那会儿,同组的同事在靶机上拧了个不起眼的小球上去,雷达屏幕上的目标回波强度直接跳了好几个量级。我当时第一反应是这玩意儿是不是偷偷带了个功放,后来才知道,那个看起来平平无奇的介质球叫龙勃透镜反射器,…

2026/10/17 2:54:45

Java Swing小游戏源码解析:森林冰火人单人版设计与实现

简介:《森林冰火人单人版》是一款基于Java开发的动作冒险小游戏,融合角色操控、收集水晶、计时闯关等机制,操作简单而逻辑完整,适合Java初学者、游戏编程爱好者以及需要课程设计参考的学生。压缩包共78个文件,包含6个j…

2026/10/17 2:54:45

基于HP6、SHT20与MPU6050的多传感器时间同步采集系统设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 2:54:45

UDP组播收发程序:Windows下网络调试的实用工具

简介:一份面向Windows网络编程开发者的UDP组播(多播)工程示例,基于Winsock应用程序接口实现数据报的发送与接收,适合正在学习网际协议多播原理、练习套接字编程的入门或进阶开发者参考。资源包共36个文件,整…

2026/10/17 2:49:45

初识C语言(mac版)

个人学习的心得记录和知识梳理1. C语言是什么?C语言是一门计算机语言,是人和计算机交流的语言。 人和人交流使用的是自然语言,如:汉语、英语、日语。 那人和计算机是怎么交流的呢?使用计算机语言; 人是通过计算机语言写的程序,给计算…

2026/10/16 5:33:43

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/16 4:03:48

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/15 13:42:16

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/17 0:04:32

PlanarSLAM:面向曼哈顿世界的点线面联合SLAM系统

简介:本资源是面向机器人视觉与SLAM研究者的C开源RGB-D SLAM系统实现,专为结构化室内场景(如办公室、走廊)设计,通过融合点、线、平面三类几何特征并引入“曼哈顿世界”假设,显著提升位姿跟踪鲁棒性与稠密地…

2026/10/17 0:04:32

TDH Workflow调度实战:从DAG依赖驱动到任务编排与故障排查

1. 从一个调度脚本说起:TDH Workflow到底在解决什么问题第一次接触TDH的Workflow,是在一个数据清洗项目里。当时团队每天要跑几十个ETL任务,任务之间有严格的先后依赖——A表清洗完才能跑B表的关联,B表跑完才能触发C表的聚合。最开…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑