策略模式
约 1357 字大约 5 分钟
理论设计模式
2026-04-06
策略模式(Strategy Pattern)是一种行为型设计模式,其核心思想是将一系列可互换的算法或行为进行封装,使它们可以相互替换,从而让算法的变化独立于使用它的客户端。
简单来说,策略模式就是用组合代替继承,将复杂且多变的业务逻辑(策略)从主类中剥离出来,封装成独立的策略类,让代码更清晰、更易于维护和扩展。
为什么需要策略模式?
在没有使用策略模式时,我们常常会遇到大量的 if-else 或 switch-case 语句来处理不同的业务场景。例如,一个电商订单系统需要根据不同的用户等级(普通、VIP、超级VIP)计算不同的折扣。
传统实现的问题:
public class OrderService {
public double calculatePrice(double price, String userType) {
if ("NORMAL".equals(userType)) {
return price; // 无折扣
} else if ("VIP".equals(userType)) {
return price * 0.9; // 9折
} else if ("SUPER_VIP".equals(userType)) {
return price * 0.8 - 10; // 8折再减10元
}
return price;
}
}这种实现方式存在明显缺陷:
- 违反开闭原则:当需要新增一种用户类型(如“黑卡用户”)时,必须修改
calculatePrice方法,增加新的else if分支。 - 代码臃肿,难以维护:所有业务逻辑都堆积在一个方法里,随着业务复杂度增加,这个方法会变得极其庞大和混乱。
- 难以复用:折扣计算的逻辑被硬编码在订单服务中,无法在其他地方(如购物车)复用。
策略模式正是为了解决这些问题而生的。
策略模式的结构
策略模式由三个核心角色组成:
- 抽象策略(Strategy):定义所有具体策略必须实现的公共接口或抽象类。
- 具体策略(Concrete Strategy):实现抽象策略接口,封装了具体的算法或行为。
- 上下文(Context):持有一个策略对象的引用,并对外提供统一的调用接口。它不关心具体使用哪个策略,只负责调用策略的方法。
策略模式实战:重构电商折扣计算
让我们用策略模式来重构上面的折扣计算案例。
1. 定义抽象策略接口
// 1. 抽象策略:定义折扣计算的统一接口
public interface DiscountStrategy {
double calculate(double originalPrice);
}2. 实现具体策略类
// 2.1 具体策略:普通用户折扣(无折扣)
public class NormalDiscount implements DiscountStrategy {
@Override
public double calculate(double originalPrice) {
System.out.println("普通用户:无折扣");
return originalPrice;
}
}
// 2.2 具体策略:VIP用户折扣(9折)
public class VipDiscount implements DiscountStrategy {
@Override
public double calculate(double originalPrice) {
System.out.println("VIP用户:9折优惠");
return originalPrice * 0.9;
}
}
// 2.3 具体策略:超级VIP折扣(8折+满100减10)
public class SuperVipDiscount implements DiscountStrategy {
@Override
public double calculate(double originalPrice) {
System.out.println("超级VIP用户:8折+满100减10");
double price = originalPrice * 0.8;
if (price >= 100) {
price -= 10;
}
return price;
}
}3. 创建上下文类
// 3. 上下文:订单类,持有策略对象
public class Order {
private DiscountStrategy discountStrategy; // 持有策略接口
private double originalPrice;
public Order(double originalPrice, DiscountStrategy discountStrategy) {
this.originalPrice = originalPrice;
this.discountStrategy = discountStrategy;
}
// 动态切换策略
public void setDiscountStrategy(DiscountStrategy discountStrategy) {
this.discountStrategy = discountStrategy;
}
// 计算最终价格
public double getFinalPrice() {
if (discountStrategy == null) {
throw new IllegalStateException("折扣策略未设置");
}
return discountStrategy.calculate(originalPrice);
}
}4. 客户端调用
public class Client {
public static void main(String[] args) {
// 创建订单,初始为普通用户
Order order = new Order(200.0, new NormalDiscount());
System.out.println("最终价格: " + order.getFinalPrice());
// 运行时动态切换为VIP策略
order.setDiscountStrategy(new VipDiscount());
System.out.println("最终价格: " + order.getFinalPrice());
// 运行时动态切换为超级VIP策略
order.setDiscountStrategy(new SuperVipDiscount());
System.out.println("最终价格: " + order.getFinalPrice());
}
}策略模式的优缺点
优点
- 符合开闭原则:新增算法或策略时,只需增加新的策略类,无需修改任何现有代码(如上下文类)。
- 消除条件语句:用清晰的对象组合替代了复杂的
if-else或switch-case判断,使代码更简洁、可读性更高。 - 提高代码复用性:每个策略都是独立的类,可以在不同的上下文中被复用。
- 算法可自由切换:客户端可以在运行时根据需要动态地选择和切换策略。
缺点
- 客户端必须了解所有策略:客户端需要知道所有可用的策略类,并自行决定使用哪一个。这有时会将选择的复杂性暴露给客户端。
- 增加类的数量:每增加一个策略,就会多一个类,可能会增加系统的复杂度。
常见应用场景
策略模式在实际开发中应用非常广泛,以下是一些典型场景:
- 多种支付方式:如支付宝、微信、银行卡支付,每种支付方式都是一个独立的策略。
- 多种排序算法:根据数据量和类型选择不同的排序算法(如快速排序、归并排序)。
- 游戏角色技能:角色的不同攻击方式(近战、远程、魔法)可以封装为不同的策略。
- 电商促销活动:满减、折扣、优惠券等不同的促销规则。
- Spring框架中的应用:Spring的
ResourceLoader接口就是策略模式的典型应用,它可以根据不同的资源路径(如classpath:、file:、http:)选择不同的资源加载策略。
