Strategy(策略模式)
策略模式是一种行为型设计模式,核心是定义一系列算法,将每个算法封装起来并使它们可相互替换。通过这种方式,算法的变化不会影响使用算法的客户端,从而实现算法的独立变化与复用。
一、核心定义与目的
二、关键特性
三、典型应用场景
四、优缺点分析
分类 | 具体内容 |
| 1. 降低耦合:客户端与具体算法解耦,算法变化不影响客户端; 2. 增强扩展性:新增算法只需实现抽象策略接口,无需修改现有代码,符合开闭原则; 3. 简化测试:每个策略类独立封装,可单独进行单元测试; 4. 避免条件判断:用策略切换替代 if-else 分支,使代码更清晰、易维护; 5. 算法复用:策略类可在多个客户端间共享,减少代码重复。 |
| 1. 类数量增加:每个算法对应一个策略类,策略过多时会导致系统中类的数量激增; 2. 客户端需了解策略:客户端必须知道所有策略的存在才能选择合适的策略,增加了客户端的使用成本; 3. 策略状态管理复杂:若策略需要维护状态,可能需要额外的机制(如上下文类)来管理,增加系统复杂度; 4. 不适用于简单场景:若仅2-3个简单算法且无需频繁切换,使用策略模式会过度设计。 |
五、核心角色与结构
角色名称 | 职责描述 |
抽象策略(Strategy) | 定义所有具体策略的统一接口(或抽象类),声明策略的核心方法(算法入口);客户端通过此接口与策略交互。 |
具体策略(Concrete Strategy) | 实现抽象策略接口,封装具体的算法逻辑;多个具体策略类对应不同的算法实现。 |
上下文(Context) | 持有抽象策略的引用,负责策略的创建、切换和管理;提供方法供客户端设置或获取当前策略;在需要时调用当前策略的算法方法。 |
客户端(Client) | 创建具体策略实例,并通过上下文设置当前策略;调用上下文的方法触发算法执行,无需直接操作具体策略。 |
策略模式类图:

客户端通过上下文设置策略,上下文将算法执行委托给当前策略;客户端可随时通过上下文切换策略。
六、实现示例(C#)
以“电商折扣计算”为例,系统需支持3种折扣策略:会员折扣(9折)、节日折扣(8折)、促销折扣(满1000减200),通过策略模式实现折扣算法的灵活切换。
1. 抽象策略(Strategy)
/// /// 抽象折扣策略接口
/// 定义折扣计算的统一方法
///
public interface IDiscountStrategy
{
///
/// 计算折扣后金额
///
/// 原价
/// 折扣后金额
decimal Calculate(decimal originalPrice);
}2. 具体策略(Concrete Strategy)
/// /// 具体策略1:会员折扣(9折)
///
public class MemberDiscountStrategy : IDiscountStrategy
{
public decimal Calculate(decimal originalPrice)
{
Console.WriteLine("使用会员折扣(9折)");
return originalPrice * 0.9m;
}
}
/// /// 具体策略2:节日折扣(8折)
///
public class HolidayDiscountStrategy : IDiscountStrategy
{
public decimal Calculate(decimal originalPrice)
{
Console.WriteLine("使用节日折扣(8折)");
return originalPrice * 0.8m;
}
}
/// /// 具体策略3:促销折扣(满1000减200)
///
public class PromotionDiscountStrategy : IDiscountStrategy
{
public decimal Calculate(decimal originalPrice)
{
Console.WriteLine("使用促销折扣(满1000减200)");
return originalPrice >= 1000 ? originalPrice - 200 : originalPrice;
}
}3. 上下文(Context)
/// /// 上下文:折扣计算器
/// 管理策略的切换和调用
///
public class DiscountCalculator
{
// 持有当前策略的引用
private IDiscountStrategy _currentStrategy;
/// /// 初始化上下文,默认使用会员折扣
/// public DiscountCalculator()
{
_currentStrategy = new MemberDiscountStrategy();
}
/// /// 设置当前折扣策略(允许动态切换)
///
public void SetStrategy(IDiscountStrategy strategy)
{
_currentStrategy = strategy;
}
/// /// 计算最终价格(委托给当前策略)
///
public decimal CalculateFinalPrice(decimal originalPrice)
{
return _currentStrategy.Calculate(originalPrice);
}
}4. 客户端(Client)
/// /// 客户端:模拟不同场景下的折扣计算
///
class Program
{
static void Main(string[ ] args)
{
// 创建上下文(折扣计算器)
var calculator = new DiscountCalculator();
decimal originalPrice = 1500m;
Console.WriteLine($"商品原价:{originalPrice:C}");
// 1. 使用默认策略(会员折扣)
decimal memberPrice = calculator.CalculateFinalPrice(originalPrice);
Console.WriteLine($"会员折扣后价格:{memberPrice:C}");
Console.WriteLine("------------------------");
// 2. 切换为节日折扣策略
calculator.SetStrategy(new HolidayDiscountStrategy());
decimal holidayPrice = calculator.CalculateFinalPrice(originalPrice);
Console.WriteLine($"节日折扣后价格:{holidayPrice:C}");
Console.WriteLine("------------------------");
// 3. 切换为促销折扣策略
calculator.SetStrategy(new PromotionDiscountStrategy());
decimal promotionPrice = calculator.CalculateFinalPrice(originalPrice);
Console.WriteLine($"促销折扣后价格:{promotionPrice:C}");
}
}输出结果
商品原价:¥1,500.00
使用会员折扣(9折)
会员折扣后价格:¥1,350.00
------------------------
使用节日折扣(8折)
节日折扣后价格:¥1,200.00
------------------------
使用促销折扣(满1000减200)
促销折扣后价格:¥1,300.00七、总结
策略模式的核心是“算法封装与动态切换”,通过将算法与客户端分离,解决了算法多样性带来的代码臃肿问题,同时提高了系统的扩展性和可维护性。实际开发中,需根据算法数量、变化频率和切换需求决定是否使用:当算法多变且需要灵活选择时,策略模式是理想方案;当算法简单且固定时,直接实现可能更高效。
八、培训PPT
因无法上传附件需要跳转下方链接查看
https://alidocs.dingtalk.com/i/nodes/wva2dxOW4kD9MK70T4ywk9dm8bkz3BRL?doc_type=wiki_doc