发布时间:2025-06-24 17:32:53  作者:北方职教升学中心  阅读量:912


这种模式特别适合以下场景:

  • 需要在运行时动态切换算法的场景
  • 有一组类似的算法,只是具体实现不同
  • 算法的使用者不需要知道算法的具体实现
  • 需要消除一系列的条件语句

2. 策略模式的结构

策略模式主要包含以下三个角色:

  1. Strategy(策略接口):定义所有支持的算法的公共接口
  2. ConcreteStrategy(具体策略):实现了Strategy接口的具体算法
  3. Context(上下文):持有一个Strategy的引用,用于调用具体的算法

3. UML类图

«interface»
Strategy
+algorithm()
ConcreteStrategyA
+algorithm()
ConcreteStrategyB
+algorithm()
ConcreteStrategyC
+algorithm()
Context
-strategy: Strategy
+setStrategy(Strategy)
+executeStrategy()

UML类图说明

  1. Strategy(策略接口)
    • 这是策略模式的核心,定义了算法的公共接口
    • 通常只包含一个用于执行算法的方法
    • 可以包含算法所需的参数
  2. ConcreteStrategy(具体策略)
    • 实现了Strategy接口定义的算法
    • 包含算法的具体逻辑
    • 可以有多个不同的实现
  3. Context(上下文)
    • 维护一个对Strategy对象的引用
    • 负责在运行时设置具体的策略
    • 调用策略对象的算法方法

4. 代码实现

让我们通过一个支付方式的例子来实现策略模式:

支付策略示例说明

在电商系统中,通常需要支持多种支付方式(支付宝、微信支付、策略模式让算法的变化独立于使用算法的客户端。

好的设计模式应该解决实际问题,而不是增加不必要的复杂性。

目录

  • 1. 什么是策略模式
  • 2. 策略模式的结构
  • 3. UML类图
  • 4. 代码实现
  • 5. 策略模式 vs if-else
  • 6. 常见应用场景
  • 7. 优缺点分析
  • 8. 最佳实践建议

1. 什么是策略模式

策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。这是策略模式的典型应用场景,因为:

  1. 每种支付方式的具体实现不同
  2. 需要在运行时根据用户选择切换支付方式
  3. 支付处理逻辑应该独立于具体的支付方式

完整代码实现

// 支付策略接口publicinterfacePaymentStrategy{/**     * 处理支付     * @param amount 支付金额     * @return 支付是否成功     */booleanpay(doubleamount);}// 支付宝支付策略publicclassAlipayStrategyimplementsPaymentStrategy{privateStringalipayAccount;publicAlipayStrategy(StringalipayAccount){this.alipayAccount =alipayAccount;}@Overridepublicbooleanpay(doubleamount){// 实际项目中这里会调用支付宝SDKSystem.out.println("使用支付宝账户"+alipayAccount +"支付"+amount +"元");returntrue;}}// 微信支付策略publicclassWeChatPayStrategyimplementsPaymentStrategy{privateStringwechatId;publicWeChatPayStrategy(StringwechatId){this.wechatId =wechatId;}@Overridepublicbooleanpay(doubleamount){// 实际项目中这里会调用微信支付SDKSystem.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()方法接收支付金额作为参数
  • 设计为接口而不是抽象类,提供更大的灵活性
具体策略类分析
  1. AlipayStrategy
    • 实现支付宝支付逻辑
    • 需要支付宝账户信息
  2. WeChatPayStrategy
    • 实现微信支付逻辑
    • 需要微信ID信息
  3. 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");}}}

对比分析

  1. 代码组织
    • if-else:所有逻辑集中在一个方法中,代码臃肿
    • 策略模式:每个算法独立封装,结构清晰
  2. 扩展性
    • if-else:添加新支付方式需要修改原有代码
    • 策略模式:只需添加新的策略类,无需修改现有代码
  3. 维护性
    • if-else:逻辑耦合,修改一个分支可能影响其他分支
    • 策略模式:各个策略相互独立,易于维护
  4. 测试性
    • if-else:需要测试所有分支的组合
    • 策略模式:可以独立测试每个策略

6. 常见应用场景

  1. 支付系统
    • 多种支付方式
    • 支付渠道的动态选择
  2. 排序算法
    • 不同的排序策略
    • 根据数据特征选择最优算法
  3. 压缩算法
    • 不同的压缩方式
    • 根据文件类型选择压缩算法
  4. 验证策略
    • 多种验证方式
    • 根据安全级别选择验证方式

7. 优缺点分析

优点

  1. 算法族的封装:每个算法独立封装,易于维护和扩展
  2. 消除条件语句:避免复杂的if-else结构
  3. 运行时切换:可以动态改变对象的行为
  4. 开闭原则:添加新策略无需修改现有代码

缺点

  1. 策略类数量增加:每个策略都需要一个类,可能导致类数量增多
  2. 客户端需要了解策略:客户端需要知道所有的策略,以便选择
  3. 增加了对象数量:每个策略都是一个对象,会占用更多内存

8. 最佳实践建议

  1. 策略的创建
// 使用工厂模式创建策略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;}}

为什么这样更好?

  • 集中管理策略的创建逻辑,避免策略创建逻辑分散
  • 客户端代码不需要知道具体策略的构造细节
  • 可以轻松实现策略的单例模式或对象池
  • 便于添加策略创建的前置检查和后置处理
  1. 策略的缓存
publicclassPaymentContext{privatestaticfinalMap<String,PaymentStrategy>strategyCache =newConcurrentHashMap<>();publicPaymentStrategygetStrategy(Stringtype){returnstrategyCache.computeIfAbsent(type,k ->createStrategy(k));}privatePaymentStrategycreateStrategy(Stringtype){// 创建策略的逻辑}}

为什么这样更好?

  • 避免重复创建相同的策略对象,节省内存
  • 提高获取策略的性能,特别是策略创建成本较高时
  • 使用ConcurrentHashMap保证线程安全
  • computeIfAbsent保证原子性,避免并发问题
  1. 策略的参数化
publicinterfacePaymentStrategy{booleanpay(PaymentContextcontext,doubleamount);}publicclassPaymentContext{privateMap<String,Object>parameters =newHashMap<>();publicvoidaddParameter(Stringkey,Objectvalue){parameters.put(key,value);}publicObjectgetParameter(Stringkey){returnparameters.get(key);}}

为什么这样更好?

  • 避免策略接口参数过多,提高接口的稳定性
  • 支持动态添加新参数,不需要修改接口
  • 参数可以在运行时动态变化
  • 便于添加参数的验证和转换逻辑
  1. 策略的验证 - 使用模板方法规范流程
publicabstractclassAbstractPaymentStrategyimplementsPaymentStrategy{@Overridepublicfinalbooleanpay(doubleamount){if(!validate(amount)){returnfalse;}returndoPayment(amount);}protectedabstractbooleanvalidate(doubleamount);protectedabstractbooleandoPayment(doubleamount);}

为什么这样更好?

- **使用模板方法模式规范策略执行流程**- **强制子类实现必要的验证逻辑**- **避免重复编写流程控制代码**- **便于统一添加日志、在使用策略模式时,应该始终关注它是否真正简化了你的代码结构,是否提高了代码的可维护性和可扩展性。单例模式)结合使用,以实现更复杂的功能。

在实际应用中,策略模式常常与其他模式(如工厂模式、相比传统的if-else方式,策略模式提供了更好的代码组织方式和更强的扩展性。银行卡等)。选择使用策略模式时,需要权衡类的数量增加和代码维护性之间的关系。监控等横切关注点**

总结

策略模式是一种强大的行为型设计模式,它通过将算法族封装在独立的类中,实现了算法的动态切换。