目录
- 1. 什么是策略模式
- 2. 策略模式的结构
- 3. UML类图
- 4. 代码实现
- 5. 策略模式 vs if-else
- 6. 常见应用场景
- 7. 优缺点分析
- 8. 最佳实践建议
1. 什么是策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。这是策略模式的典型应用场景,因为:
- 每种支付方式的具体实现不同
- 需要在运行时根据用户选择切换支付方式
- 支付处理逻辑应该独立于具体的支付方式
完整代码实现
publicinterfacePaymentStrategy{booleanpay(doubleamount);}publicclassAlipayStrategyimplementsPaymentStrategy{privateStringalipayAccount;publicAlipayStrategy(StringalipayAccount){this.alipayAccount =alipayAccount;}@Overridepublicbooleanpay(doubleamount){System.out.println("使用支付宝账户"+alipayAccount +"支付"+amount +"元");returntrue;}}publicclassWeChatPayStrategyimplementsPaymentStrategy{privateStringwechatId;publicWeChatPayStrategy(StringwechatId){this.wechatId =wechatId;}@Overridepublicbooleanpay(doubleamount){System.out.println("使用微信账户"+wechatId +"支付"+amount +"元");returntrue;}}publicclassBankCardStrategyimplementsPaymentStrategy{privateStringcardNumber;privateStringcvv;privateStringdateOfExpiry;publicBankCardStrategy(StringcardNumber,Stringcvv,StringdateOfExpiry){this.cardNumber =cardNumber;this.cvv =cvv;this.dateOfExpiry =dateOfExpiry;}@Overridepublicbooleanpay(doubleamount){System.out.println("使用银行卡"+cardNumber +"支付"+amount +"元");returntrue;}}publicclassPaymentContext{privatePaymentStrategypaymentStrategy;publicvoidsetPaymentStrategy(PaymentStrategystrategy){this.paymentStrategy =strategy;}publicbooleanprocessPayment(doubleamount){if(paymentStrategy ==null){thrownewIllegalStateException("必须设置支付策略");}returnpaymentStrategy.pay(amount);}}publicclassClient{publicstaticvoidmain(String[]args){PaymentContextcontext =newPaymentContext();doubleamount =100.0;context.setPaymentStrategy(newAlipayStrategy("alice@email.com"));context.processPayment(amount);context.setPaymentStrategy(newWeChatPayStrategy("wxid_123456"));context.processPayment(amount);context.setPaymentStrategy(newBankCardStrategy("1234-5678-9012-3456","123","12/24"));context.processPayment(amount);}}
代码详细说明
PaymentStrategy(Strategy)
- 定义了支付算法的统一接口
pay()
方法接收支付金额作为参数- 设计为接口而不是抽象类,提供更大的灵活性
具体策略类分析
- AlipayStrategy
- WeChatPayStrategy
- BankCardStrategy
PaymentContext(Context)角色分析
- 持有PaymentStrategy的引用
- 提供设置策略的方法
- 委托具体策略执行支付操作
- 包含基本的空值检查
5. 策略模式 vs if-else
传统if-else方式
publicclassTraditionalPayment{publicbooleanprocessPayment(StringpaymentType,doubleamount,Map<String,String>paymentInfo){if("alipay".equals(paymentType)){StringalipayAccount =paymentInfo.get("account");System.out.println("使用支付宝账户"+alipayAccount +"支付"+amount +"元");returntrue;}elseif("wechat".equals(paymentType)){StringwechatId =paymentInfo.get("wechatId");System.out.println("使用微信账户"+wechatId +"支付"+amount +"元");returntrue;}elseif("bankcard".equals(paymentType)){StringcardNumber =paymentInfo.get("cardNumber");System.out.println("使用银行卡"+cardNumber +"支付"+amount +"元");returntrue;}else{thrownewIllegalArgumentException("Unsupported payment type");}}}
对比分析
- 代码组织
- if-else:所有逻辑集中在一个方法中,代码臃肿
- 策略模式:每个算法独立封装,结构清晰
- 扩展性
- if-else:添加新支付方式需要修改原有代码
- 策略模式:只需添加新的策略类,无需修改现有代码
- 维护性
- if-else:逻辑耦合,修改一个分支可能影响其他分支
- 策略模式:各个策略相互独立,易于维护
- 测试性
- if-else:需要测试所有分支的组合
- 策略模式:可以独立测试每个策略
6. 常见应用场景
- 支付系统
- 排序算法
- 压缩算法
- 验证策略
7. 优缺点分析
优点
- 算法族的封装:每个算法独立封装,易于维护和扩展
- 消除条件语句:避免复杂的if-else结构
- 运行时切换:可以动态改变对象的行为
- 开闭原则:添加新策略无需修改现有代码
缺点
- 策略类数量增加:每个策略都需要一个类,可能导致类数量增多
- 客户端需要了解策略:客户端需要知道所有的策略,以便选择
- 增加了对象数量:每个策略都是一个对象,会占用更多内存
8. 最佳实践建议
- 策略的创建
publicclassPaymentStrategyFactory{privatestaticMap<String,PaymentStrategy>strategies =newHashMap<>();static{strategies.put("alipay",newAlipayStrategy("default@email.com"));strategies.put("wechat",newWeChatPayStrategy("default_wxid"));strategies.put("bankcard",newBankCardStrategy("default_card","123","12/24"));}publicstaticPaymentStrategygetStrategy(Stringtype){PaymentStrategystrategy =strategies.get(type);if(strategy ==null){thrownewIllegalArgumentException("Invalid payment type: "+type);}returnstrategy;}}
为什么这样更好?
- 集中管理策略的创建逻辑,避免策略创建逻辑分散
- 客户端代码不需要知道具体策略的构造细节
- 可以轻松实现策略的单例模式或对象池
- 便于添加策略创建的前置检查和后置处理
- 策略的缓存
publicclassPaymentContext{privatestaticfinalMap<String,PaymentStrategy>strategyCache =newConcurrentHashMap<>();publicPaymentStrategygetStrategy(Stringtype){returnstrategyCache.computeIfAbsent(type,k ->createStrategy(k));}privatePaymentStrategycreateStrategy(Stringtype){}}
为什么这样更好?
- 避免重复创建相同的策略对象,节省内存
- 提高获取策略的性能,特别是策略创建成本较高时
- 使用ConcurrentHashMap保证线程安全
- computeIfAbsent保证原子性,避免并发问题
- 策略的参数化
publicinterfacePaymentStrategy{booleanpay(PaymentContextcontext,doubleamount);}publicclassPaymentContext{privateMap<String,Object>parameters =newHashMap<>();publicvoidaddParameter(Stringkey,Objectvalue){parameters.put(key,value);}publicObjectgetParameter(Stringkey){returnparameters.get(key);}}
为什么这样更好?
- 避免策略接口参数过多,提高接口的稳定性
- 支持动态添加新参数,不需要修改接口
- 参数可以在运行时动态变化
- 便于添加参数的验证和转换逻辑
- 策略的验证 - 使用模板方法规范流程
publicabstractclassAbstractPaymentStrategyimplementsPaymentStrategy{@Overridepublicfinalbooleanpay(doubleamount){if(!validate(amount)){returnfalse;}returndoPayment(amount);}protectedabstractbooleanvalidate(doubleamount);protectedabstractbooleandoPayment(doubleamount);}
为什么这样更好?
- **使用模板方法模式规范策略执行流程**- **强制子类实现必要的验证逻辑**- **避免重复编写流程控制代码**- **便于统一添加日志、在使用策略模式时,应该始终关注它是否真正简化了你的代码结构,是否提高了代码的可维护性和可扩展性。单例模式)结合使用,以实现更复杂的功能。在实际应用中,策略模式常常与其他模式(如工厂模式、相比传统的if-else方式,策略模式提供了更好的代码组织方式和更强的扩展性。银行卡等)。选择使用策略模式时,需要权衡类的数量增加和代码维护性之间的关系。监控等横切关注点**
总结
策略模式是一种强大的行为型设计模式,它通过将算法族封装在独立的类中,实现了算法的动态切换。