前言:当代码开始"耍脾气"

各位程序猿/程序媛们,有没有遇到过这样的场景:你的代码里充斥着大量的if-else语句,每次新增一个功能就要在原有的条件判断上再添一笔?就像是你家的遥控器,按钮越来越多,最后连你自己都记不住哪个是干嘛的?

别担心,今天我要介绍的策略模式就是来解决这个问题的https://images.alixixi.com/uploads/20250928/img_68d8c4255057730.png它就像是给你的代码装上一个智能遥控器,每个功能都有独立的按钮,清晰又方便https://images.alixixi.com/uploads/20250928/img_68d8c4255057730.png

行为设计模式:代码的"社交礼仪"

在深入策略模式之前,我们先快速了解一下行为设计模式这个大家族。它们主要关注的是对象之间的通信和职责分配,就像是教代码如何优雅地"社交":

  • 职责链模式:像击鼓传花,让请求在对象链中传递
  • 命令模式:把请求封装成对象,实现解耦
  • 观察者模式:我变了,马上通知所有关注我的人
  • 策略模式:今天的主角,让算法独立于使用它的客户

策略模式:算法的"变形金刚"

什么是策略模式?

策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。它让算法的变化独立于使用算法的客户。

简单说就是:把会变化的部分提取出来,封装成独立的策略类

为什么要使用策略模式?

想象一下,如果你是一个电商平台的开发者,需要实现不同的折扣策略:

没有策略模式的"灾难现场":

public BigDecimal calculateDiscount(String userType, BigDecimal price) {
    if ("VIP".equals(userType)) {
        return price.multiply(new BigDecimal("0.8"));
    } else if ("SVIP".equals(userType)) {
        return price.multiply(new BigDecimal("0.7"));
    } else if ("NEW_USER".equals(userType)) {
        return price.multiply(new BigDecimal("0.9"));
    } else if ("EMPLOYEE".equals(userType)) {
        return price.multiply(new BigDecimal("0.6"));
    }
    // 每次新增用户类型都要修改这里https://images.alixixi.com/uploads/20250928/img_68d8c4255057730.png
    return price;
}

这种代码的痛点:

  • 违反开闭原则(对修改关闭,对扩展开放)
  • 代码臃肿,难以维护
  • 可测试性差

策略模式的设计思想

策略模式的核心思想:识别变化,封装变化

就像玩乐高,你把不同的功能模块化,需要什么就拼接什么,而不是把所有的功能都固化在一个大块里。

策略模式实战:折扣计算大改造

第一步:定义策略接口

public interface DiscountStrategy {
    /**
     * 计算折扣价
     * @param price 原价
     * @return 折扣价
     */
    BigDecimal calculate(BigDecimal price);
    
    /**
     * 获取策略类型
     * @return 策略类型
     */
    String getType();
}

第二步:实现具体策略

// VIP折扣策略
public class VipDiscountStrategy implements DiscountStrategy {
    @Override
    public BigDecimal calculate(BigDecimal price) {
        return price.multiply(new BigDecimal("0.8"));
    }
    
    @Override
    public String getType() {
        return "VIP";
    }
}

// 超级VIP折扣策略
public class SuperVipDiscountStrategy implements DiscountStrategy {
    @Override
    public BigDecimal calculate(BigDecimal price) {
        return price.multiply(new BigDecimal("0.7"));
    }
    
    @Override
    public String getType() {
        return "SVIP";
    }
}

// 新用户折扣策略
public class NewUserDiscountStrategy implements DiscountStrategy {
    @Override
    public BigDecimal calculate(BigDecimal price) {
        return price.multiply(new BigDecimal("0.9"));
    }
    
    @Override
    public String getType() {
        return "NEW_USER";
    }
}

第三步:策略上下文

public class DiscountContext {
    private DiscountStrategy strategy;
    
    public DiscountContext(DiscountStrategy strategy) {
        this.strategy = strategy;
    }
    
    // 设置策略(支持动态切换)
    public void setStrategy(DiscountStrategy strategy) {
        this.strategy = strategy;
    }
    
    // 执行计算
    public BigDecimal executeStrategy(BigDecimal price) {
        if (strategy == null) {
            throw new IllegalStateException("请先设置折扣策略");
        }
        System.out.println("使用" + strategy.getType() + "折扣策略");
        return strategy.calculate(price);
    }
}

第四步:客户端使用

public class StrategyDemo {
    public static void main(String[] args) {
        // 创建价格
        BigDecimal price = new BigDecimal("100");
        
        // 普通用户
        DiscountContext context = new DiscountContext(new VipDiscountStrategy());
        System.out.println("VIP价格:" + context.executeStrategy(price));
        
        // 动态切换为超级VIP
        context.setStrategy(new SuperVipDiscountStrategy());
        System.out.println("超级VIP价格:" + context.executeStrategy(price));
        
        // 新用户
        context.setStrategy(new NewUserDiscountStrategy());
        System.out.println("新用户价格:" + context.executeStrategy(price));
    }
}

输出结果:

使用VIP折扣策略
VIP价格:80
使用SVIP折扣策略
超级VIP价格:70
使用NEW_USER折扣策略
新用户价格:90

策略模式的进阶玩法

策略工厂模式

为了避免每次都要new具体的策略类,我们可以结合工厂模式:

public class DiscountStrategyFactory {
    private static final Map<String, DiscountStrategy> strategies = new HashMap<>();
    
    static {
        strategies.put("VIP", new VipDiscountStrategy());
        strategies.put("SVIP", new SuperVipDiscountStrategy());
        strategies.put("NEW_USER", new NewUserDiscountStrategy());
    }
    
    public static DiscountStrategy getStrategy(String type) {
        DiscountStrategy strategy = strategies.get(type);
        if (strategy == null) {
            throw new IllegalArgumentException("不支持的折扣类型:" + type);
        }
        return strategy;
    }
    
    // 注册新策略(支持动态扩展)
    public static void registerStrategy(String type, DiscountStrategy strategy) {
        strategies.put(type, strategy);
    }
}

使用方式:

// 从工厂获取策略
DiscountStrategy strategy = DiscountStrategyFactory.getStrategy("VIP");
DiscountContext context = new DiscountContext(strategy);
BigDecimal result = context.executeStrategy(price);

Spring Boot中的策略模式

在Spring Boot中,我们可以利用依赖注入让策略模式更加优雅:

@Service
public class DiscountService {
    private final Map<String, DiscountStrategy> strategyMap;
    
    // 通过构造函数注入所有策略
    public DiscountService(List<DiscountStrategy> strategies) {
        this.strategyMap = strategies.stream()
            .collect(Collectors.toMap(DiscountStrategy::getType, Function.identity()));
    }
    
    public BigDecimal calculateDiscount(String userType, BigDecimal price) {
        DiscountStrategy strategy = strategyMap.get(userType);
        if (strategy == null) {
            throw new IllegalArgumentException("不支持的折扣类型:" + userType);
        }
        return strategy.calculate(price);
    }
}

策略模式的应用场景

适合使用策略模式的场景:

  1. 支付方式选择:支付宝、微信、银联等不同支付方式
  2. 数据导出格式:Excel、PDF、CSV等不同格式导出
  3. 排序算法:冒泡排序、快速排序、归并排序等
  4. 缓存策略:LRU、FIFO、LFU等缓存淘汰算法
  5. 消息通知:短信、邮件、钉钉、微信等通知方式

不适合使用策略模式的场景:

  1. 算法很少变化:如果算法基本不变,过度设计反而复杂
  2. 客户端必须了解具体策略:如果客户端需要知道策略的具体实现细节

策略模式的优势总结

  1. 开闭原则:新增策略无需修改现有代码
  2. 避免条件判断:告别复杂的if-else语句
  3. 代码复用:策略可以在多个环境中使用
  4. 易于测试:每个策略都可以独立测试
  5. 运行时切换:可以动态改变对象的行为

结语:让代码"活"起来

策略模式就像是给我们的代码装上了"变形金刚"的能力,让算法能够灵活变换。它教会我们一个重要的编程哲学:拥抱变化,而不是抗拒变化

下次当你看到代码中又出现大段的if-else时,不妨想想:"这里是不是可以用策略模式来优化?"

记住,好的代码不是一次性写出来的,而是不断重构出来的。策略模式就是我们重构工具箱中一件强大的武器https://images.alixixi.com/uploads/20250928/img_68d8c4255057730.png


互动环节:大家在工作中还遇到过哪些适合使用策略模式的场景?欢迎在评论区分享你的实战经验

本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]