深度对比简单工厂模式和策略模式 简单工厂模式 vs 策略模式UML看着像核心职责、使用场景、目的完全不同一、先纠正你的直观错觉UML结构只是类组成相似但角色分工、依赖方向、解决问题天差地别先统一两套模式标准UML角色再对比差异。1. 两套模式标准UML角色拆解1简单工厂模式静态工厂角色构成抽象产品 Product所有产品统一抽象接口比如Operation加减乘除运算具体产品 ConcreteProductA/B/C实现抽象产品的具体类Add、Sub、Mul工厂 Factory核心唯一创建者提供静态方法createProduct(type)根据参数判断new 对应具体产品实例返回抽象产品。客户端 Client只依赖「工厂」「抽象产品」不直接new具体产品客户端把创建参数传给工厂由工厂全权负责实例创建。UML关系Factory → 依赖 ProductFactory 实例化 ConcreteProductClient → 依赖 Factory Product核心动作工厂负责「对象创建」。2策略模式角色构成抽象策略 Strategy统一算法接口比如PayStrategy支付微信/支付宝/银行卡具体策略 ConcreteStrategyA/B/C实现抽象策略写不同算法逻辑WechatPay、AliPay上下文 Context核心持有一个Strategy成员变量对外提供业务方法execute()内部调用策略的算法提供setStrategy()动态切换策略。客户端 Client自己new具体策略实例传给Context客户端自主选择要使用的策略。UML关系Context 聚合 Strategy持有引用Client → 依赖 Context Strategy核心动作上下文负责「使用算法/执行业务」策略只封装可变算法。二、最核心4点本质区别重点区别1设计目标、解决的问题完全不同简单工厂解决「对象创建复杂」的问题痛点产品种类多、创建逻辑复杂、创建参数耦合在业务代码里不想让客户端到处new XXX()。核心职责封装实例化过程统一对象创建入口。关注点怎么造对象变化点新增产品时只改工厂的if/switch判断分支违反开闭原则这也是简单工厂不属于GOF23设计模式的原因策略模式解决「算法/业务逻辑频繁变化、大量if-else业务分支」的问题痛点同一个业务流程多种可替换算法大量if-else嵌套在业务类中难以维护、扩展。核心职责把可变算法抽离独立类实现算法与业务解耦动态切换。关注点怎么使用对象、运行时切换行为变化点新增算法只需要新增ConcreteStrategy完全不用改Context符合开闭原则区别2核心主控角色完全不一样简单工厂核心 工厂类 Factory所有实例创建逻辑全部收拢在工厂工厂是整个流程的控制中心客户端只告诉工厂“我要什么类型”创建过程完全交给工厂客户端不参与new具体类。示例客户端传typeadd工厂内部new Add()返回给客户端。策略模式核心 上下文 ContextContext是业务载体负责串联固定业务流程策略只是一段可替换的逻辑。客户端自己创建具体策略注入ContextContext只负责调用策略不负责创建策略。示例客户端ctx new OrderContext(); ctx.setStrategy(new WechatPay()); ctx.pay();区别3客户端权责、实例创建权归属不同简单工厂客户端不创建具体对象工厂全权创建// 简单工厂客户端代码OperationopOperationFactory.createOperation();// 客户端只传标识不new Addintresop.calc(1,2);客户端只持有抽象产品完全不感知具体产品类实例创建逻辑被屏蔽在工厂内部。策略模式客户端必须手动创建具体策略注入上下文// 策略模式客户端代码PayStrategypaynewWechatPay();// 客户端自己new具体策略OrderContextctxnewOrderContext(pay);ctx.doPay(99);// 运行时动态切换ctx.setStrategy(newAliPay());客户端明确知道自己要用哪一个具体策略Context不会主动创建策略只负责持有、调用策略。区别4开闭原则支持度、扩展代价不同简单工厂不满足开闭原则新增一个产品必须修改工厂里的分支判断if/switch修改原有代码会引入bug风险。例新增除法Div要去OperationFactory加case / : return new Div()。策略模式完美满足开闭原则新增算法只新增一个ConcreteStrategy实现类Context、原有策略完全不用修改无侵入。例新增数字人民币支付新建DigitalRMBPay实现PayStrategy上下文一行不用改。三、举同场景对比示例直观感受差异场景计算器支持加减乘除四种运算方案A用简单工厂实现抽象产品Operation提供calc(int a,int b)具体产品Add、Sub、Mul、Div工厂OperationFactory静态方法根据符号返回运算实例客户端只传符号由工厂创建运算对象执行计算重心怎么把加减乘除的new操作统一管理起来避免业务代码到处new。方案B用策略模式实现抽象策略CalcStrategy提供calc(int a,int b)具体策略AddStrategy、SubStrategy…上下文CalcContext持有CalcStrategy提供execute()执行计算客户端手动new AddStrategy传给CalcContext调用execute随时替换策略重心计算是固定业务流程加减乘除是可变算法做到运行时切换算法、解耦业务和计算逻辑。四、为什么UML图看起来几乎一样表层相似点只有2个都存在「抽象父接口 多个具体实现类」的分层都有一个中间类工厂/上下文依赖顶层抽象接口。但底层本质完全相反中间类的职责不同工厂造对象上下文用对象实例创建主体不同工厂内部new vs 客户端外部new设计目的不同封装创建逻辑 vs 封装可变算法扩展特性不同违反开闭 vs 遵循开闭。五、快速选择判断口诀如果你想统一管理对象的创建过程屏蔽复杂new逻辑 → 简单工厂如果你有同一套业务流程、多种可替换算法想消除大量if-else、运行时切换逻辑 → 策略模式如果你既要动态切换算法又不想客户端手动new策略 → 可以策略简单工厂组合使用工厂负责创建策略注入Context。六、补充组合使用案例解决策略模式客户端要new的痛点把简单工厂嵌入策略模式工厂负责创建策略客户端只传标识既拥有开闭特性又屏蔽创建逻辑// 工厂创建策略PayStrategystrategyStrategyFactory.getStrategy(wechat);OrderContextctxnewOrderContext(strategy);ctx.doPay();此时策略模式负责解耦业务与支付算法简单工厂负责屏蔽策略实例的创建细节二者各司其职互不冲突。C 策略模式完整实战示例业务场景商场收银系统3种优惠算法可动态切换正常原价收费打折如8折满减满300减100同一套收银流程优惠算法可运行时替换完美契合策略模式。模式角色对应抽象策略 StrategyCashStrategy统一收费算法接口具体策略 ConcreteStrategy正常收费/打折/满减各自实现计费逻辑上下文 ContextCashContext持有策略对象对外提供统一收银接口负责执行算法客户端 Client选择策略、传入上下文、执行计费#includeiostream#includememory// 1. 抽象策略类收费算法接口 classCashStrategy{public:virtual~CashStrategy()default;// 接收原价返回实际收款金额virtualdoubleacceptCash(doublemoney)const0;};// 2. 具体策略实现类 // 策略1正常收费无优惠classCashNormal:publicCashStrategy{public:doubleacceptCash(doublemoney)constoverride{returnmoney;}};// 策略2打折收费构造传入折扣0.88折classCashRebate:publicCashStrategy{private:doublerebate;public:explicitCashRebate(doubler):rebate(r){}doubleacceptCash(doublemoney)constoverride{returnmoney*rebate;}};// 策略3满减收费满condition减reduceclassCashReturn:publicCashStrategy{private:doublecondition;// 满多少doublereduce;// 减多少public:CashReturn(doublecond,doublered):condition(cond),reduce(red){}doubleacceptCash(doublemoney)constoverride{if(moneycondition){// 支持多次满减如满300减100600减200doubletimesmoney/condition;returnmoney-times*reduce;}returnmoney;}};// 3. 上下文 Context收银上下文 // 核心持有策略对象封装固定收银流程对外屏蔽算法细节classCashContext{private:std::unique_ptrCashStrategystrategy;// 持有策略聚合关系public:// 构造注入策略explicitCashContext(std::unique_ptrCashStrategys):strategy(std::move(s)){}// 运行时动态切换策略voidsetStrategy(std::unique_ptrCashStrategys){strategystd::move(s);}// 统一对外收银接口内部调用策略算法doublegetResult(doublemoney)const{returnstrategy-acceptCash(money);}};// 4. 客户端测试代码 intmain(){doubleoriginMoney1000;// 商品原价1000元std::cout 1. 使用原价策略 std::endl;CashContextctx1(std::make_uniqueCashNormal());std::cout应付金额ctx1.getResult(originMoney)std::endl;std::cout\n 2. 使用8折优惠策略 std::endl;CashContextctx2(std::make_uniqueCashRebate(0.8));std::cout应付金额ctx2.getResult(originMoney)std::endl;std::cout\n 3. 使用满300减100策略 std::endl;CashContextctx3(std::make_uniqueCashReturn(300,100));std::cout应付金额ctx3.getResult(originMoney)std::endl;std::cout\n 4. 运行时动态切换策略原价 → 5折 std::endl;CashContextctx4(std::make_uniqueCashNormal());std::cout切换前ctx4.getResult(originMoney)std::endl;// 动态替换算法无需修改上下文代码ctx4.setStrategy(std::make_uniqueCashRebate(0.5));std::cout切换后ctx4.getResult(originMoney)std::endl;return0;}输出结果 1. 使用原价策略 应付金额1000 2. 使用8折优惠策略 应付金额800 3. 使用满300减100策略 应付金额700 4. 运行时动态切换策略原价 → 5折 切换前1000 切换后500核心特性解读对应策略模式本质算法与业务解耦计费优惠逻辑全部抽离为独立策略类收银上下文CashContext只关心“收钱”这个固定业务不关心优惠怎么算。运行时动态切换setStrategy()可以在程序运行中替换算法不需要新建上下文对象。符合开闭原则新增优惠活动比如满赠、积分抵扣只需要新建CashStrategy派生类不用修改Context和原有策略代码。UML关系说明CashContext聚合CashStrategy持有指针/智能指针多个具体类继承抽象策略客户端创建具体策略注入上下文上下文不负责创建策略和简单工厂最核心区别和简单工厂的关键区分结合这段代码策略模式客户端自己make_uniqueCashRebate(0.8)创建策略上下文只使用、不生产对象简单工厂会单独写CashFactory客户端只传字符串rebate工厂内部new CashRebate屏蔽创建细节组合使用方案可以新增工厂类封装策略的创建解决客户端手动new策略繁琐的问题。拓展策略简单工厂 混合改造简化客户端新增工厂客户端不用手动new各种策略只传类型标识classCashStrategyFactory{public:staticstd::unique_ptrCashStrategycreateStrategy(conststd::stringtype){if(typenormal)returnstd::make_uniqueCashNormal();elseif(typerebate8)returnstd::make_uniqueCashRebate(0.8);elseif(typereturn300_100)returnstd::make_uniqueCashReturn(300,100);elsereturnstd::make_uniqueCashNormal();}};// 客户端简化写法CashContextctx(CashStrategyFactory::createStrategy(rebate8));C 简单工厂模式完整示例业务场景四则计算器加减乘除运算由工厂统一创建运算对象客户端只传运算符不手动 new 具体运算类。模式角色抽象产品 ProductOperation运算基类定义计算接口具体产品 ConcreteProductAdd、Sub、Mul、Div加减乘除工厂 FactoryOperationFactory静态方法根据标识创建对应运算实例客户端 Client只依赖工厂抽象产品屏蔽所有创建细节#includeiostream#includememory// 1. 抽象产品运算基类 classOperation{public:virtual~Operation()default;virtualdoublecalc(doublea,doubleb)const0;};// 2. 具体产品四则运算 // 加法classAdd:publicOperation{public:doublecalc(doublea,doubleb)constoverride{returnab;}};// 减法classSub:publicOperation{public:doublecalc(doublea,doubleb)constoverride{returna-b;}};// 乘法classMul:publicOperation{public:doublecalc(doublea,doubleb)constoverride{returna*b;}};// 除法classDiv:publicOperation{public:doublecalc(doublea,doubleb)constoverride{if(b0){std::cerr除数不能为0std::endl;return0;}returna/b;}};// 3. 简单工厂负责创建运算对象 classOperationFactory{public:// 静态工厂方法根据运算符创建对应运算实例staticstd::unique_ptrOperationcreateOperation(charop){switch(op){case:returnstd::make_uniqueAdd();case-:returnstd::make_uniqueSub();case*:returnstd::make_uniqueMul();case/:returnstd::make_uniqueDiv();default:std::cerr不支持的运算符std::endl;returnnullptr;}}};// 4. 客户端调用 intmain(){doublenum110,num22;// 客户端只传入运算符完全不用 new Add/Sub/Mul/DivautoopAddOperationFactory::createOperation();std::cout10 2 opAdd-calc(num1,num2)std::endl;autoopSubOperationFactory::createOperation(-);std::cout10 - 2 opSub-calc(num1,num2)std::endl;autoopMulOperationFactory::createOperation(*);std::cout10 * 2 opMul-calc(num1,num2)std::endl;autoopDivOperationFactory::createOperation(/);std::cout10 / 2 opDiv-calc(num1,num2)std::endl;return0;}运行输出10 2 12 10 - 2 8 10 * 2 20 10 / 2 5核心特点简单工厂标志性特征创建逻辑全部收拢在工厂所有new操作都在createOperation内部客户端看不到具体子类违反开闭原则如果新增「取余%」运算必须修改工厂里的switch分支改动原有代码工厂是唯一创建入口客户端只能通过工厂获取对象无权直接实例化具体产品关注点对象创建只解决“如何生产对象”不负责对象的业务执行。和之前策略模式的核心对比结合两份代码简单工厂工厂负责 new 对象客户端只拿抽象产品直接调用方法没有 Context 上下文策略模式客户端自己 new 策略对象注入 ContextContext 只使用策略绝不创建策略组合用法可以把简单工厂嵌入策略模式由工厂帮客户端创建策略简化调用。