策略模式

策略模式:灵活切换算法的设计智慧

一、策略模式的核心定义

策略模式(Strategy Pattern) 是一种行为型设计模式,它定义了一系列可替换的算法(策略),将每个算法封装成独立的类,使得算法可以在不改变客户端代码的前提下动态切换。其核心思想是:分离算法的定义与使用,通过 “组合” 替代 “继承”,让程序更具灵活性和扩展性。

简单来说,策略模式就像旅行时选择交通方式 —— 目的地(核心目标)不变,但可根据距离、成本、时间等因素,灵活切换飞机、高铁、自驾等策略(算法),且切换过程不影响旅行的整体流程。

二、策略模式的核心结构

策略模式包含三个关键角色,职责划分明确,确保算法的解耦与复用:

  1. 环境类(Context):持有策略接口的引用,负责调用具体策略执行逻辑,是客户端与策略类的中间层(客户端无需直接操作策略)。

  2. 策略接口(Strategy):定义所有具体策略的统一接口 / 抽象类,规范算法的核心方法(如 “计算价格”“执行排序” 等)。

  3. 具体策略类(Concrete Strategy):实现策略接口,封装具体的算法逻辑(如不同的折扣规则、排序算法等)。

结构示意图(简化):

Strategy(策略接口)

   ↑

├───────┬───────┬───────┤

StrategyA(策略A) StrategyB(策略B) StrategyC(策略C)

   ↑

Context(环境类)

三、策略模式的代码实现(Java 示例)

以 “电商平台折扣计算” 为例:核心需求是根据用户类型(普通用户、VIP 用户、会员用户)应用不同的折扣策略,且支持后续新增折扣规则(如节日折扣)。

1. 策略接口(DiscountStrategy)

定义折扣计算的统一方法,规范所有具体策略的实现:

// 折扣策略接口

public interface DiscountStrategy {

   // 计算折扣后价格:参数为原价

   double calculateDiscount(double originalPrice);

}

2. 具体策略类(Concrete Strategy)

实现不同用户类型的折扣算法,每个策略独立封装:

// 普通用户策略:无折扣

public class NormalUserStrategy implements DiscountStrategy {

   @Override

   public double calculateDiscount(double originalPrice) {

       return originalPrice; // 原价返回

   }

}

// VIP用户策略:9折优惠

public class VipUserStrategy implements DiscountStrategy {

   @Override

   public double calculateDiscount(double originalPrice) {

       return originalPrice * 0.9; // 9折计算

   }

}

// 会员用户策略:8折优惠 + 满100减20

public class MemberUserStrategy implements DiscountStrategy {

   @Override

   public double calculateDiscount(double originalPrice) {

       double discountPrice = originalPrice * 0.8; // 先打8折

       return discountPrice >= 100 ? discountPrice - 20 : discountPrice; // 满100减20

   }

}

3. 环境类(OrderContext)

持有策略接口引用,提供切换策略的方法,统一调用策略逻辑:

public class OrderContext {

   private DiscountStrategy discountStrategy; // 持有策略引用

   // 构造方法初始化策略(也可通过setter动态切换)

   public OrderContext(DiscountStrategy discountStrategy) {

       this.discountStrategy = discountStrategy;

   }

   // 动态切换策略(核心:支持运行时更换算法)

   public void setDiscountStrategy(DiscountStrategy discountStrategy) {

       this.discountStrategy = discountStrategy;

   }

   // 统一调用策略的算法,返回最终价格

   public double calculateFinalPrice(double originalPrice) {

       return discountStrategy.calculateDiscount(originalPrice);

   }

}

4. 客户端调用(测试代码)

通过环境类切换不同策略,无需修改客户端逻辑即可更换算法:

public class Client {

   public static void main(String[] args) {

       double originalPrice = 200.0; // 商品原价200元

       // 1. 普通用户下单(无折扣)

       OrderContext order = new OrderContext(new NormalUserStrategy());

       System.out.println("普通用户最终价格:" + order.calculateFinalPrice(originalPrice) + "元");

       // 输出:普通用户最终价格:200.0元

       // 2. 切换为VIP用户策略(9折)

       order.setDiscountStrategy(new VipUserStrategy());

       System.out.println("VIP用户最终价格:" + order.calculateFinalPrice(originalPrice) + "元");

       // 输出:VIP用户最终价格:180.0元

       // 3. 切换为会员用户策略(8折+满100减20)

       order.setDiscountStrategy(new MemberUserStrategy());

       System.out.println("会员用户最终价格:" + order.calculateFinalPrice(originalPrice) + "元");

       // 输出:会员用户最终价格:140.0元(200*0.8=160,160-20=140)

       // 4. 新增节日策略(无需修改原有代码,符合开闭原则)

       order.setDiscountStrategy(new FestivalDiscountStrategy());

       System.out.println("节日活动最终价格:" + order.calculateFinalPrice(originalPrice) + "元");

       // 输出:节日活动最终价格:150.0元

   }

   // 新增节日折扣策略(7.5折):无需修改Context或其他策略类

   static class FestivalDiscountStrategy implements DiscountStrategy {

       @Override

       public double calculateDiscount(double originalPrice) {

           return originalPrice * 0.75;

       }

   }

}

四、策略模式的核心优势

  1. 遵循开闭原则:新增策略时无需修改原有代码(如新增节日折扣),只需新增具体策略类,降低代码耦合。

  2. 算法灵活切换:运行时可通过setDiscountStrategy动态更换策略(如用户升级为 VIP 后即时切换折扣规则),无需重启程序。

  3. 代码结构清晰:每个策略独立封装,避免了大量if-else判断(如无需写 “if 是普通用户则无折扣,if 是 VIP 则 9 折...”)。

  4. 复用性强:策略类可在不同场景中复用(如会员折扣策略可同时用于订单、积分兑换等模块)。

五、策略模式的应用场景

  1. 多种算法可选:如排序算法(冒泡、快速、归并排序)、支付方式(微信、支付宝、银行卡支付)、日志输出方式(控制台、文件、数据库存储)。

  2. 避免复杂条件判断:当代码中出现多个if-elseswitch分支,且每个分支对应一个独立算法时,适合用策略模式重构。

  3. 动态切换算法:如电商平台的促销活动(日常折扣、节日折扣、限时秒杀)、游戏中的角色技能(不同技能对应不同伤害计算逻辑)。

  4. 框架中的应用:Java 的Comparator接口(排序策略)、Spring 的Resource接口(资源加载策略)、MyBatis 的Executor(执行器策略,如 SIMPLE、REUSE、BATCH)。

六、使用注意事项

  1. 策略数量控制:若策略过多(如 10 个以上),会导致类数量激增,可结合工厂模式封装策略的创建逻辑(如DiscountStrategyFactory)。

  2. 策略的无状态性:建议让具体策略类成为无状态的(不存储实例变量),可复用同一个策略对象(如NormalUserStrategy可创建单例)。

  3. 客户端需了解策略:客户端需要知道不同策略的区别(如普通用户和 VIP 用户的折扣差异),才能选择合适的策略,若策略复杂,可搭配解释器模式或配置文件优化。

  4. 避免过度设计:若算法固定且无需扩展,无需使用策略模式,直接编写简单逻辑即可。

posted @ 2025-12-06 22:18  圣祖帝皇  阅读(23)  评论(0)    收藏  举报