策略模式:算法族与可替换行为

FreeGuideOnline 最新 2026-06-18

策略模式:算法族与可替换行为

策略模式是一种行为型设计模式,它定义了一系列算法,将每个算法封装到具有共同接口的独立类中,并使它们可以相互替换。该模式让算法的变化独立于使用算法的客户端,从而在运行时动态切换行为,避免冗长的条件判断。

为什么需要策略模式

在开发中经常会遇到“根据条件执行不同行为”的需求。最直接的做法是使用 if-elseswitch-case 进行硬编码,但随着条件分支增多,代码会变得臃肿、难以维护和扩展。策略模式通过将每个分支逻辑抽取为独立的策略类,解决了以下问题:

  • 消除复杂的条件判断语句,提高可读性。
  • 增加新策略时无需修改现有客户端代码,符合开闭原则。
  • 各策略类可以独立测试、复用,降低了耦合度。

核心结构

策略模式通常包含三个角色:

  • 策略接口(Strategy):定义所有策略类必须实现的公共方法,通常是一个行为抽象。
  • 具体策略(Concrete Strategy):实现策略接口的具体算法类。
  • 上下文(Context):持有一个策略接口的引用,负责将客户端的调用委派给当前策略对象。
+----------------+            +---------------------+
|    Context     |            | <<interface>>       |
|----------------|            | Strategy            |
| - strategy: Strategy        |---------------------|
| + setStrategy(Strategy)     | + execute()         |
| + executeStrategy()         |                     |
+----------------+            +---------------------+
         |                                ^
         |                                |
         |                    +-----------+-----------+
         |                    |                       |
         |            +-----------------+   +-----------------+
         +----------->| ConcreteStrategyA|   | ConcreteStrategyB|
                      |-----------------|   |-----------------|
                      | + execute()     |   | + execute()     |
                      +-----------------+   +-----------------+

策略模式的实现步骤

  1. 识别变化部分:将容易发生变化的行为(算法、规则、业务逻辑)抽象出来。
  2. 定义策略接口:创建一个接口,声明所有可变行为需要遵循的公共方法。
  3. 实现具体策略:将每种变化封装为独立类,实现策略接口。
  4. 构建上下文类:在上下文类中组合策略接口,并提供方法供客户端动态切换策略。
  5. 客户端调用:客户端根据具体场景选择并设置策略,然后通过上下文执行行为。

代码演示(Java 示例)

假设我们有一个支付系统,支持多种支付方式(支付宝、微信支付、银行卡)。使用策略模式可以这样设计:

步骤1:定义支付策略接口

public interface PaymentStrategy {
    void pay(double amount);
}

步骤2:实现具体策略类

public class AlipayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用支付宝支付 " + amount + " 元");
    }
}

public class WechatPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用微信支付 " + amount + " 元");
    }
}

public class CardPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用银行卡支付 " + amount + " 元");
    }
}

步骤3:定义上下文订单类

public class Order {
    private PaymentStrategy paymentStrategy;

    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    public void checkout(double amount) {
        if (paymentStrategy == null) {
            throw new IllegalStateException("请先选择支付方式");
        }
        paymentStrategy.pay(amount);
    }
}

步骤4:客户端使用

public class Client {
    public static void main(String[] args) {
        Order order = new Order();

        // 使用支付宝支付
        order.setPaymentStrategy(new AlipayStrategy());
        order.checkout(100.0);

        // 动态切换为微信支付
        order.setPaymentStrategy(new WechatPayStrategy());
        order.checkout(200.0);
    }
}

通过上述设计,新增一种支付方式时,只需要增加一个新的策略类并实现 PaymentStrategy 接口,无需改动 Order 类或其他已有代码。

实战场景:电商促销折扣计算

在电商系统中,不同用户等级享受不同的折扣策略(普通用户无折扣、VIP 用户 9 折、SVIP 用户 8 折)。传统做法可能写满 if 判断,但使用策略模式可以让促销逻辑更优雅:

  1. 定义 DiscountStrategy 接口,包含 calculatePrice(originalPrice) 方法。
  2. 实现 NormalDiscountVipDiscountSvipDiscount
  3. ShoppingCart 上下文中组合 DiscountStrategy,结算时动态选择策略。

这样,当需要新增“节日闪购 5 折”策略时,只需新建一个类即可,完全符合开闭原则。

策略模式与其它设计模式的结合

  • 工厂模式:通常与策略模式结合,由工厂负责根据参数创建对应的策略对象,进一步降低客户端对具体策略类的依赖。
  • 单例模式:如果策略类本身无状态,可以设计为单例,避免反复创建对象。
  • 模板方法模式:可以在策略接口的骨架中定义算法步骤,让具体策略实现部分细节。
  • 状态模式:二者结构相似,但策略模式是让客户端主动切换算法,状态模式则是对象内部状态改变时自动切换行为。

优缺点一览

优点

  • 避免多重条件判断,代码清晰。
  • 符合开闭原则,新增策略无需修改已有代码。
  • 策略类可以独立测试、复用,提升可维护性。
  • 运行时灵活切换算法,增强系统扩展性。

缺点

  • 增加了类的数量,每个策略都是一个类,可能造成类膨胀。
  • 客户端必须了解各个策略之间的差异,以便选择合适的策略。
  • 策略类之间无法共享数据,除非通过上下文传递公共参数。

最佳实践与注意事项

  • 策略无状态化:尽量让策略对象不持有状态,确保线程安全,并可复用。
  • 使用函数式接口:在 Java 8+ 中,若策略接口只有一个方法,可以直接用 Lambda 表达式代替具体策略类,进一步简化代码。
  • 避免过度设计:只有当一个行为有至少两三种变体时才考虑策略模式,否则简单的 if-else 可能更直观。
  • 结合配置化:将策略的选择逻辑配置在配置文件或数据库中,可以在不重新发布的情况下动态改变行为。

策略模式的核心思想是“封装变化”,将行为抽象为可互换的组件。合理使用该模式可以使系统更加灵活、可扩展,是应对复杂业务规则变化的有力工具。