🔍 一、策略模式是什么?

策略模式(Strategy Pattern) 是一种行为型设计模式,它定义了一系列算法(策略),把它们一个个封装起来,并且使它们可以互相替换。
这种模式让算法的变化独立于使用它的客户端。


🧠 二、通俗理解

策略模式就像是“选择做事的方法”。

想象你要出行:

  • 你可以选择 开车骑自行车打车坐地铁
    这些就是“策略”。
    而你自己就是“上下文”——根据情况选择一个出行策略来完成目标。


🧱 三、结构图(UML)

+--------------------+      +----------------------------+
|     Context        |      |       Strategy(接口)     |
|--------------------|      +----------------------------+
| - strategy:Strategy|<---- | + Execute(): void          |
|--------------------|      +----------------------------+
| + SetStrategy()    |             ▲
| + ExecuteStrategy()|             |
+--------------------+      +----------------------------+
                            | ConcreteStrategyA           |
                            | + Execute(): void           |
                            +----------------------------+
                            | ConcreteStrategyB           |
                            | + Execute(): void           |
                            +----------------------------+

🔧 四、角色说明

角色

说明

Strategy

抽象策略:定义所有具体策略必须实现的方法

ConcreteStrategy

具体策略:实现具体的行为

Context

上下文:维护一个对策略对象的引用,并通过它来调用策略定义的方法


🧩 五、代码示例(简化版)

例子:支付策略(微信 / 支付宝)

// 策略接口
public interface IPaymentStrategy
{
    void Pay(decimal amount);
}

// 具体策略
public class WeChatPay : IPaymentStrategy
{
    public void Pay(decimal amount) => Console.WriteLine($"使用微信支付 {amount} 元");
}

public class AliPay : IPaymentStrategy
{
    public void Pay(decimal amount) => Console.WriteLine($"使用支付宝支付 {amount} 元");
}

// 上下文
public class PaymentContext
{
    private IPaymentStrategy _strategy;

    public void SetStrategy(IPaymentStrategy strategy)
    {
        _strategy = strategy;
    }

    public void Pay(decimal amount)
    {
        _strategy.Pay(amount);
    }
}

使用:

PaymentContext context = new PaymentContext();
context.SetStrategy(new WeChatPay());
context.Pay(100); // 输出:使用微信支付 100 元

💡 六、适用场景

策略模式适合以下场景:

  • 需要在运行时动态选择不同算法/行为时;

  • 需要避免大量 if-else / switch-case 分支判断;

  • 同一个任务可以有多种处理方式

  • 希望通过策略类复用行为逻辑时。


✅ 七、优点

优点

描述

✔️ 开闭原则

新增策略只需添加类,无需修改原逻辑

✔️ 消除复杂条件判断

用多态代替大量的 if-else

✔️ 可复用策略

同一策略可在多个上下文中使用

✔️ 解耦上下文与算法实现

策略变化不影响使用方


❌ 八、缺点

缺点

描述

❗ 增加类数量

每种策略都需要一个类,可能类爆炸

❗ 客户端需要知道所有策略

必须理解每种策略适用的场景

❗ 策略切换逻辑可能下放到客户端

如果没有合适的策略选择器,就容易造成使用困难


📦 九、常见应用场景

场景

描述

排序算法选择

比如策略封装了不同排序算法(快排/归并/冒泡)

支付方式

支持多种支付通道

AI 行为树

不同行为封装成策略

游戏攻击模式

玩家角色或敌人的攻击策略切换

物流状态处理

状态封装为策略(如你写的案例)


🧭 十、与其他模式的区别

  • 状态模式:策略侧重于行为选择,而状态模式强调状态转换和内部变化

  • 工厂模式:工厂负责“创建对象”,策略负责“使用对象行为”。


🔚 总结

特点

描述

设计原则体现

开闭原则、依赖倒置

核心思想

将“行为”封装成独立类,并由上下文持有和选择

成本

类的数量可能变多,但换来更高的灵活性和扩展性


实践代码🧭🧭🧭🧭

使用一个线上商城 订单的例子 表述策略模式

using System;
using System.Collections.Generic;

namespace DesignPatternsPractice.Src.Behavioral.StrategyPatternRefactor
{
    /// <summary>
    /// 启动入口
    /// </summary>
    public class StrategyPatternDemo
    {
        static void Main()
        {
            Order order = new Order(OrderStatus.Shipping, "冰激凌");

            // 用 OrderService 来处理与订单相关的业务 (多嵌套了一层)
            OrderService orderService = new OrderService(new StrategySelector());

            string customerPhone = orderService.GetCustomerSupportPhone(order);

            Console.WriteLine($"客服电话为: {customerPhone}");
        }
    }

    #region 核心业务类和接口

    /// <summary>
    /// 策略接口(改名为更有语义)
    /// </summary>
    public interface ICustomerSupportStrategy
    {
        string GetCustomerServicePhone();
    }

    /// <summary>
    /// Shipping 状态的策略实现
    /// </summary>
    public class ShippingStrategy : ICustomerSupportStrategy
    {
        public string GetCustomerServicePhone() => "1302020003";
    }

    public class NotShippedStrategy : ICustomerSupportStrategy
    {
        public string GetCustomerServicePhone() => "13912345678";
    }

    public class InTransitStrategy : ICustomerSupportStrategy
    {
        public string GetCustomerServicePhone() => "13887654321";
    }

    public class ArrivedStrategy : ICustomerSupportStrategy
    {
        public string GetCustomerServicePhone() => "13711223344";
    }

    public class DeliveredStrategy : ICustomerSupportStrategy
    {
        public string GetCustomerServicePhone() => "13699887766";
    }

    #endregion

    #region 策略选择器(负责根据状态返回正确的策略)

    public class StrategySelector
    {
        // 策略注册表:职责从 OrderService 中提取出来了
        private readonly Dictionary<OrderStatus, ICustomerSupportStrategy> _strategyMap;

        public StrategySelector()
        {
            // 字典初始化。可以考虑延迟实例化或使用 DI 容器
            _strategyMap = new Dictionary<OrderStatus, ICustomerSupportStrategy>
            {
                { OrderStatus.Shipping, new ShippingStrategy() },
                { OrderStatus.NotShipped, new NotShippedStrategy() },
                { OrderStatus.InTransit, new InTransitStrategy() },
                { OrderStatus.Arrived, new ArrivedStrategy() },
                { OrderStatus.Delivered, new DeliveredStrategy() }
            };
        }

        /// <summary>
        /// 根据订单状态返回对应的策略
        /// </summary>
        public ICustomerSupportStrategy Select(OrderStatus status)
        {
            if (_strategyMap.TryGetValue(status, out var strategy))
            {
                return strategy;
            }

            throw new Exception($"无法处理的订单状态: {status}");
        }
    }

    #endregion

    #region 业务封装类

    /// <summary>
    /// 订单服务类:业务层,组合使用策略选择器
    /// </summary>
    public class OrderService
    {
        private readonly StrategySelector _strategySelector;

        public OrderService(StrategySelector strategySelector)
        {
            _strategySelector = strategySelector;
        }

        public string GetCustomerSupportPhone(Order order)
        {
            var strategy = _strategySelector.Select(order.GetStatus());
            return strategy.GetCustomerServicePhone();
        }
    }

    #endregion

    #region 数据类和枚举

    public class Order
    {
        private readonly OrderStatus _status;
        private readonly string _name;

        public Order(OrderStatus status, string name)
        {
            _status = status;
            _name = name;
        }

        public OrderStatus GetStatus() => _status;
        public string GetName() => _name;
    }

    /// <summary>
    /// 订单状态(原 OrderType,更符合语义)
    /// </summary>
    public enum OrderStatus
    {
        Shipping,
        NotShipped,
        InTransit,
        Arrived,
        Delivered
    }

    #endregion
}