策略模式

策略模式(Strategy Pattern)是一种行为型设计模式,它允许在运行时动态选择算法或行为,通过将一系列可互换的算法封装到独立的策略类中,使客户端代码可以灵活地切换不同策略。它强调行为的封装和替换,常用于需要根据不同条件选择不同实现逻辑的场景。

策略模式的组成

策略模式通常包含以下几个角色:

  1. 上下文(Context):持有策略对象的引用,并提供接口供客户端调用,负责将请求委托给当前策略。
  2. 策略接口(Strategy):定义所有具体策略的公共接口,声明策略方法。
  3. 具体策略(Concrete Strategy):实现策略接口,定义具体的算法或行为。
  4. 客户端(Client):创建并配置上下文对象,设置具体的策略。

工作原理

  1. 客户端选择一个具体策略并将其注入上下文。
  2. 上下文通过策略接口调用方法,具体行为由当前策略对象执行。
  3. 客户端可以在运行时动态更换策略,改变上下文的行为。

UML 类图

┌────────────────┐
│    Context     │
├────────────────┤
│ strategy       │
│ setStrategy()  │
│ execute()      │
└────────────────┘
       ↑
       │
┌────────────────┐
│    Strategy    │
├────────────────┤
│ execute()      │
└────────────────┘
       ↑
       │
┌────────────────┐       ┌────────────────┐
│ ConcreteStrategyA │    │ ConcreteStrategyB │
├────────────────┤       ├────────────────┤
│ execute()      │       │ execute()      │
└────────────────┘       └────────────────┘

代码示例(以 Java 为例)

以下是一个策略模式的实现,模拟不同支付方式的场景:

// 策略接口
interface PaymentStrategy {
    void pay(double amount);
}

// 具体策略:信用卡支付
class CreditCardPayment implements PaymentStrategy {
    private String cardNumber;

    public CreditCardPayment(String cardNumber) {
        this.cardNumber = cardNumber;
    }

    @Override
    public void pay(double amount) {
        System.out.println("使用信用卡 " + cardNumber + " 支付 " + amount + " 元");
    }
}

// 具体策略:支付宝支付
class AlipayPayment implements PaymentStrategy {
    private String account;

    public AlipayPayment(String account) {
        this.account = account;
    }

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

// 上下文:支付上下文
class PaymentContext {
    private PaymentStrategy strategy;

    public void setStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public void executePayment(double amount) {
        if (strategy == null) {
            System.out.println("请先选择支付方式");
            return;
        }
        strategy.pay(amount);
    }
}

// 测试代码
public class Main {
    public static void main(String[] args) {
        PaymentContext context = new PaymentContext();

        // 使用信用卡支付
        context.setStrategy(new CreditCardPayment("1234-5678-9012-3456"));
        context.executePayment(100.0);

        // 切换到支付宝支付
        context.setStrategy(new AlipayPayment("user@example.com"));
        context.executePayment(200.0);
    }
}

输出:

使用信用卡 1234-5678-9012-3456 支付 100.0 元
使用支付宝 user@example.com 支付 200.0 元

策略模式的特点

  • 优点
  • 将算法或行为封装到独立类中,符合单一职责原则。
  • 支持运行时动态切换策略,灵活性高。
  • 替代了大量的条件语句(如 if-elseswitch),提高代码可读性和维护性。
  • 符合开闭原则,新增策略只需添加新的具体策略类。
  • 缺点
  • 如果策略数量较多,会增加类的数量,系统复杂度可能上升。
  • 客户端需要了解所有策略的实现细节以选择合适的策略。

使用场景

  1. 当需要根据不同条件选择不同算法或行为时:
  • 支付系统(如信用卡、支付宝、微信支付)。
  • 排序算法(如快速排序、归并排序)。
  • 压缩算法(如 ZIP、RAR)。
  1. 需要动态切换行为或算法的场景:
  • 游戏中角色的攻击方式(如近战、远程)。
  • 日志记录方式(如文件日志、数据库日志)。
  1. 替代大量条件语句的场景。

注意事项

  • 与状态模式的区别
  • 策略模式侧重于选择不同的算法或行为,策略间通常独立,无状态转换。
  • 状态模式侧重于根据对象状态切换行为,状态间可能存在转换关系。
  • 策略的选择:可以由客户端显式设置策略,也可以通过工厂模式自动选择策略以降低客户端的负担。
  • 复用性:策略对象通常无状态,可使用单例模式或静态实例以减少内存开销。
  • 扩展性:新增策略时,只需实现策略接口并创建新类,无需修改上下文代码。

总结

策略模式通过将不同算法或行为封装到独立的策略类中,实现了行为的动态切换和解耦。它适用于需要灵活选择算法或行为的场景,能有效减少条件语句并提高代码的可扩展性和维护性。在支付系统、算法选择和行为切换等场景中,策略模式是常见且高效的设计选择。

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注