Java 23 种设计模式:从踩坑到精通 | 番外:简单工厂模式 —— 物流计费策略实战

📅 2026/7/23 21:31:56
Java 23 种设计模式:从踩坑到精通 | 番外:简单工厂模式 —— 物流计费策略实战
Java 23 种设计模式从踩坑到精通 | 番外简单工厂模式 —— 物流计费策略实战摘要简单工厂模式虽然不是 GoF 23 种设计模式之一但在实际开发中使用频率极高。它通过一个工厂类根据参数决定创建哪种具体产品让客户端无需直接new对象。本文结合智能物流中“根据订单类型创建不同计费策略”的场景完整展示简单工厂的实现并与工厂方法模式深度对比帮你掌握“参数化创建”的设计精髓。《Java 23 种设计模式从踩坑到精通》开篇系列介绍与目录 正篇简单工厂模式 Factory —— 还在写一坨 if-else 创建对象吗 当前番外 · 简单工厂模式 × 物流计费策略 返回系列总目录1. 物流计费场景的痛点物流平台支持多种计费策略——标准件按“重量×距离”算加急件费率翻倍还要加服务费大件重货则按“首重续重”阶梯计费。如果每个订单服务都自己写计算逻辑代码会变成一坨if-elseif(standard.equals(type)){costweight*distance*0.5;}elseif(express.equals(type)){costweight*distance*0.5*250;}elseif(heavy.equals(type)){// 大件逻辑...}简单工厂的解决思路用一个工厂类封装所有策略的创建逻辑客户端只需传入类型参数即可拿到对应实例让创建与使用分离。2. 简单工厂 UML物流计费场景3. 完整源码实现3.1 抽象产品计费策略接口/** * 抽象产品计费策略接口 */publicinterfaceBillingStrategy{/** * 计算运费 * param weight 重量kg * param distance 距离km * return 运费金额 */doublecalculate(doubleweight,doubledistance);/** * 获取策略名称 */StringgetStrategyName();}白话所有计费方式都必须实现这个接口——能算运费能报名字。3.2 具体产品A标准计费策略/** * 具体产品A标准计费策略 */publicclassStandardBillingimplementsBillingStrategy{privatestaticfinaldoubleBASE_RATE0.5;// 每kg每km 0.5元Overridepublicdoublecalculate(doubleweight,doubledistance){returnweight*distance*BASE_RATE;}OverridepublicStringgetStrategyName(){return标准计费普通快递;}}白话标准件按“重量 × 距离 × 0.5”算简单直接。3.3 具体产品B加急计费策略/** * 具体产品B加急计费策略 */publicclassExpressBillingimplementsBillingStrategy{privatestaticfinaldoubleBASE_RATE0.5;privatestaticfinaldoubleEXPRESS_FEE50.0;// 加急服务费Overridepublicdoublecalculate(doubleweight,doubledistance){// 加急件基础费率×2 加急服务费returnweight*distance*BASE_RATE*2EXPRESS_FEE;}OverridepublicStringgetStrategyName(){return加急计费当日达/次日达;}}白话加急件费率翻倍还要加 50 元服务费。3.4 具体产品C大件计费策略/** * 具体产品C大件计费策略 */publicclassHeavyBillingimplementsBillingStrategy{privatestaticfinaldoubleFIRST_WEIGHT30.0;// 首重30kgprivatestaticfinaldoubleFIRST_RATE100.0;// 首重费用100元privatestaticfinaldoubleADDITIONAL_RATE2.0;// 续重每kg 2元Overridepublicdoublecalculate(doubleweight,doubledistance){if(weightFIRST_WEIGHT){returnFIRST_RATE;}returnFIRST_RATE(weight-FIRST_WEIGHT)*ADDITIONAL_RATE;}OverridepublicStringgetStrategyName(){return大件计费重货专线;}}白话大件按“首重 100 元 续重每 kg 2 元”算距离不参与计算重货专线统一价。3.5 简单工厂计费策略工厂importjava.util.Map;importjava.util.concurrent.ConcurrentHashMap;/** * 简单工厂计费策略工厂 * 根据类型参数创建对应的计费策略 */publicclassBillingStrategyFactory{// 使用缓存避免重复创建享元思想privatestaticfinalMapString,BillingStrategyCACHEnewConcurrentHashMap();static{// 预注册所有策略也可通过SPI动态加载CACHE.put(standard,newStandardBilling());CACHE.put(express,newExpressBilling());CACHE.put(heavy,newHeavyBilling());}/** * 工厂方法根据类型创建计费策略 * param type 策略类型standard / express / heavy * return 对应的计费策略实例 * throws IllegalArgumentException 不支持的类型 */publicstaticBillingStrategycreateStrategy(Stringtype){BillingStrategystrategyCACHE.get(type.toLowerCase());if(strategynull){thrownewIllegalArgumentException(不支持的计费策略类型type);}System.out.println([工厂] 创建计费策略 → strategy.getStrategyName());returnstrategy;}/** * 动态注册新的计费策略扩展用 */publicstaticvoidregisterStrategy(Stringtype,BillingStrategystrategy){CACHE.put(type.toLowerCase(),strategy);}}白话工厂预先缓存所有策略客户端要什么类型就从缓存取不用每次都new。新增策略可以调用registerStrategy动态注册。3.6 客户端订单服务/** * 客户端订单服务 */publicclassOrderService{/** * 创建订单并计算运费 */publicvoidcreateOrder(StringstrategyType,doubleweight,doubledistance){System.out.println(\n═.repeat(60));System.out.println(【创建订单】策略strategyType重量weightkg距离distancekm);System.out.println(═.repeat(60));// 通过简单工厂获取策略客户端不直接newBillingStrategystrategyBillingStrategyFactory.createStrategy(strategyType);// 计算运费doublecoststrategy.calculate(weight,distance);System.out.printf(计费策略%s\n,strategy.getStrategyName());System.out.printf(运费金额%.2f 元\n,cost);}}白话订单服务不关心用的是哪种计费策略它只管找工厂要、调calculate算钱。3.7 完整测试验证/** * 测试类验证简单工厂的创建与计算 */publicclassSimpleFactoryTest{publicstaticvoidmain(String[]args){System.out.println( 简单工厂模式物流计费策略 \n);OrderServiceorderServicenewOrderService();// 场景1标准件5kg200kmorderService.createOrder(standard,5,200);// 场景2加急件5kg200kmorderService.createOrder(express,5,200);// 场景3大件重货80kg200kmorderService.createOrder(heavy,80,200);// 验证不同策略类型是否返回不同实现System.out.println(\n═.repeat(60));System.out.println(【验证】不同策略类型返回不同实现);System.out.println(═.repeat(60));BillingStrategys1BillingStrategyFactory.createStrategy(standard);BillingStrategys2BillingStrategyFactory.createStrategy(express);BillingStrategys3BillingStrategyFactory.createStrategy(heavy);System.out.println(standard 实例类型s1.getClass().getSimpleName());System.out.println(express 实例类型s2.getClass().getSimpleName());System.out.println(heavy 实例类型s3.getClass().getSimpleName());}}4. 运行结果 简单工厂模式物流计费策略 ════════════════════════════════════════════════════════════ 【创建订单】策略standard重量5.0kg距离200.0km ════════════════════════════════════════════════════════════ [工厂] 创建计费策略 → 标准计费普通快递 计费策略标准计费普通快递 运费金额500.00 元 ════════════════════════════════════════════════════════════ 【创建订单】策略express重量5.0kg距离200.0km ════════════════════════════════════════════════════════════ [工厂] 创建计费策略 → 加急计费当日达/次日达 计费策略加急计费当日达/次日达 运费金额1050.00 元 ════════════════════════════════════════════════════════════ 【创建订单】策略heavy重量80.0kg距离200.0km ════════════════════════════════════════════════════════════ [工厂] 创建计费策略 → 大件计费重货专线 计费策略大件计费重货专线 运费金额200.00 元 ════════════════════════════════════════════════════════════ 【验证】不同策略类型返回不同实现 ════════════════════════════════════════════════════════════ [工厂] 创建计费策略 → 标准计费普通快递 [工厂] 创建计费策略 → 加急计费当日达/次日达 [工厂] 创建计费策略 → 大件计费重货专线 standard 实例类型StandardBilling express 实例类型ExpressBilling heavy 实例类型HeavyBilling5. 核心角色回顾角色职责对应代码Product定义产品的抽象接口BillingStrategyConcreteProduct实现具体产品StandardBilling/ExpressBilling/HeavyBillingSimpleFactory根据参数创建具体产品BillingStrategyFactoryClient调用工厂获取产品OrderService6. 简单工厂 vs 工厂方法对比项简单工厂工厂方法工厂结构一个具体工厂类抽象工厂接口 多个具体工厂创建方式静态方法通过参数判断子类重写工厂方法扩展性新增产品需修改工厂类违反OCP新增产品只需新增工厂子类符合OCP复杂度简单适合产品种类少的场景较复杂适合产品种类多且经常扩展的场景客户端依赖依赖具体工厂类只依赖抽象工厂接口7. 简单工厂的“坑”与优化问题解决方案违反开闭原则新增产品要改工厂结合反射 配置文件动态加载工厂类职责过重产品种类增多时升级为工厂方法静态方法难以 Mock 测试改为实例方法 依赖注入三者演进关系简单工厂参数判断→ 工厂方法子类决定→ 抽象工厂产品族是一个“从集中到分散、从单产品到产品族”的演进过程。8. 六大设计原则体现原则体现单一职责工厂只负责创建策略只负责计算开闭原则新增策略需修改工厂违反可结合反射优化里氏替换所有策略可替换BillingStrategy接口依赖倒置客户端依赖BillingStrategy抽象接口接口隔离BillingStrategy接口精简只有两个方法迪米特法则客户端只与工厂和策略接口交互简单工厂 UML源码物流计费场景startuml title Java 23 种设计模式从踩坑到精通 footer 折哥 | 智能物流与Java实战 1. 全局样式配置 skinparam backgroundColor #FEFEFE skinparam shadowing false skinparam classBorderColor #333333 skinparam classFontColor #1A1A1A skinparam classFontSize 14 skinparam noteFontSize 12 skinparam noteFontColor #555555 skinparam arrowColor #555555 skinparam classBackgroundColor #F9F9F9 2. 抽象产品计费策略 interface BillingStrategy { double calculate(double weight, double distance) String getStrategyName() } note right of BillingStrategy b抽象产品Product/b -- 计费策略接口定义所有计费方式 的统一计算方法 end note 3. 具体产品A标准计费 class StandardBilling implements BillingStrategy { double calculate(double weight, double distance) String getStrategyName() } note right of StandardBilling b具体产品A/b -- 标准计费普通快递按重量×距离 基础费率计算 end note 4. 具体产品B加急计费 class ExpressBilling implements BillingStrategy { double calculate(double weight, double distance) String getStrategyName() } note right of ExpressBilling b具体产品B/b -- 加急计费加急件基础费率×2 加急服务费 end note 5. 具体产品C大件计费 class HeavyBilling implements BillingStrategy { double calculate(double weight, double distance) String getStrategyName() } note right of HeavyBilling b具体产品C/b -- 大件计费重货专线首重续重 阶梯式计费 end note 6. 简单工厂计费策略工厂 class BillingStrategyFactory { static BillingStrategy createStrategy(String type) - static final MapString, BillingStrategy CACHE } note right of BillingStrategyFactory b简单工厂SimpleFactory/b -- 根据传入的类型参数返回对应的 计费策略实例静态方法无需实例化 end note 7. 客户端 class OrderService { void createOrder(String strategyType, double weight, double distance) } note right of OrderService b客户端Client/b -- 只需传入策略类型无需关心 具体策略类的创建细节 end note 8. 关系连线 BillingStrategy |.. StandardBilling : 实现 BillingStrategy |.. ExpressBilling : 实现 BillingStrategy |.. HeavyBilling : 实现 BillingStrategyFactory .. BillingStrategy : 创建 OrderService .. BillingStrategyFactory : 调用 OrderService .. BillingStrategy : 使用 enduml 《Java 23 种设计模式从踩坑到精通》快速导航开篇系列介绍与目录正篇简单工厂模式 Factory —— 还在写一坨 if-else 创建对象吗当前番外 · 简单工厂模式 × 物流计费策略你在这里创建型模式汇总结构型模式汇总行为型模式汇总 关注《Java 23 种设计模式从踩坑到精通》用 25 篇文章彻底吃透设计模式。福利预告全系列代码及 UML 源码将在完结时统一打包开放点击「关注」「收藏」第一时间获取。 除了设计模式我也在深挖智能物流实战WMS、托盘调度、机器学习落地。欢迎点击头像看看专栏 《出版社物流WMS智能调度实战》、《电商多平台电子面单对接实战》。技术相通思路可鉴。