策略模式基础概念
策略模式(Strategy Pattern)是一种行为型设计模式,其核心思想是定义一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户端,符合开闭原则(对扩展开放,对修改关闭)。
策略模式的核心组件
- 策略接口(Strategy) - 定义所有支持的算法的公共接口
- 具体策略(ConcreteStrategy) - 实现策略接口的具体算法
- 上下文(Context) - 持有一个策略接口的引用,负责根据需要选择和使用具体策略
- 客户端(Client) - 创建并配置上下文对象,选择合适的策略
策略模式的实现
下面通过一个电商系统的折扣计算示例展示策略模式的实现:
// 策略接口 - 折扣计算
interface DiscountStrategy {
double applyDiscount(double originalPrice);
}
// 具体策略 - 无折扣
class NoDiscount implements DiscountStrategy {
@Override
public double applyDiscount(double originalPrice) {
return originalPrice;
}
}
// 具体策略 - 固定金额折扣
class FixedAmountDiscount implements DiscountStrategy {
private double discountAmount;
public FixedAmountDiscount(double discountAmount) {
this.discountAmount = discountAmount;
}
@Override
public double applyDiscount(double originalPrice) {
return Math.max(0, originalPrice - discountAmount);
}
}
// 具体策略 - 百分比折扣
class PercentageDiscount implements DiscountStrategy {
private double discountPercentage;
public PercentageDiscount(double discountPercentage) {
this.discountPercentage = discountPercentage;
}
@Override
public double applyDiscount(double originalPrice) {
return originalPrice * (1 - discountPercentage / 100);
}
}
// 上下文 - 购物车
class ShoppingCart {
private DiscountStrategy discountStrategy;
public ShoppingCart() {
// 默认无折扣
this.discountStrategy = new NoDiscount();
}
// 设置折扣策略
public void setDiscountStrategy(DiscountStrategy discountStrategy) {
this.discountStrategy = discountStrategy;
}
// 计算折扣后的价格
public double calculateTotal(double originalPrice) {
return discountStrategy.applyDiscount(originalPrice);
}
}
// 客户端代码
public class StrategyPatternClient {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
double originalPrice = 1000.0;
// 使用无折扣策略
cart.setDiscountStrategy(new NoDiscount());
System.out.println("原价: " + originalPrice);
System.out.println("无折扣价格: " + cart.calculateTotal(originalPrice));
// 使用固定金额折扣策略(减200元)
cart.setDiscountStrategy(new FixedAmountDiscount(200.0));
System.out.println("固定金额折扣价格: " + cart.calculateTotal(originalPrice));
// 使用百分比折扣策略(打8折)
cart.setDiscountStrategy(new PercentageDiscount(20.0));
System.out.println("百分比折扣价格: " + cart.calculateTotal(originalPrice));
}
}
策略模式的应用场景
- 算法选择 - 当系统需要在多个算法中动态选择一个时
- 避免条件语句 - 用策略模式替代复杂的 if-else 或 switch 语句
- 行为扩展 - 当需要在运行时动态更改对象的行为时
- 多种实现方式 - 当一个问题有多种解决方式,且需要在运行时切换时
- 权限控制 - 根据不同用户角色应用不同的访问策略
策略模式与状态模式的对比
特性 | 策略模式 | 状态模式 |
---|---|---|
核心目的 | 算法的替换和选择 | 对象状态的管理和转换 |
客户端控制 | 客户端主动选择策略 | 状态转换由上下文或状态自身控制 |
状态数量 | 策略之间无关联,数量固定 | 状态之间有关联,数量可能动态变化 |
结构复杂度 | 简单,策略之间相互独立 | 复杂,状态之间有转换逻辑 |
典型应用 | 支付方式、排序算法、折扣计算 | 工作流状态、游戏角色状态 |
策略模式的优缺点
优点:
- 符合开闭原则 - 可以在不修改原有代码的情况下新增策略
- 消除条件语句 - 避免使用大量的 if-else 或 switch 语句
- 提高代码复用性 - 策略可以被多个上下文复用
- 简化单元测试 - 每个策略可以独立测试
- 解耦算法与客户端 - 客户端不需要了解算法的具体实现
缺点:
- 类数量增加 - 每个策略都需要一个独立的类,可能导致类爆炸
- 客户端必须了解策略差异 - 客户端需要知道不同策略的区别才能选择
- 策略与上下文耦合 - 上下文需要理解策略接口,可能存在一定耦合
- 不适合简单场景 - 对于简单的算法选择,使用策略模式可能过于复杂
使用策略模式的注意事项
- 合理设计策略接口 - 确保策略接口简洁且满足需求
- 策略的创建与管理 - 可以使用工厂模式或配置文件来管理策略的创建
- 避免过度使用 - 仅在确实需要动态切换算法时使用
- 考虑策略组合 - 可以通过组合多个策略实现更复杂的行为
- 使用枚举策略 - 对于固定且简单的策略,可以考虑使用枚举实现
策略模式是一种非常实用的设计模式,它通过将算法封装并使其可互换,提高了代码的灵活性和可维护性。在实际开发中,策略模式常用于电商折扣系统、支付方式选择、游戏 AI 等需要动态选择算法的场景。