策略模式

25 阅读4分钟

1.概念

策略模式(Strategy Pattern)是一种行为型设计模式,用于在运行时选择算法的行为。它允许你定义一系列算法,并将其封装在可相互替换的策略对象中,从而使算法的选择与使用算法的客户端代码分离。

在策略模式中,有三个核心角色:

  1. 环境(Context):它持有一个策略对象的引用,并在运行时根据需要将工作委派给策略对象。环境对象通常具有一个接口或抽象类作为类型,以与策略对象进行交互。
  2. 策略(Strategy):它是一个接口或抽象类,定义了具体策略类所必须实现的方法。不同的具体策略类实现了不同的算法或行为。
  3. 具体策略(Concrete Strategies):它是策略接口的具体实现,包含算法的具体逻辑。

2.结构图

image.png

3.示例代码

class Program
{
    static void Main(string[] args)
    {
        var list = new List<Product>();
        var apple = new Product("苹果", 10000, new NoDiscountStrategy());
        var xiaomi = new Product("小米", 3999, new FixedDiscountStrategy(200));
        var huawei = new Product("华为", 5000, new PercentageDiscountStrategy(Convert.ToDecimal(0.9)));
        list.Add(apple);
        list.Add(xiaomi);
        list.Add(huawei);
        foreach(var product in list)
        {
            Console.WriteLine("{0},折后价为:{1}", product.Name, product.CaculateDiscountPrice());
        }
    }
}
// 抽象策略接口,包含一个计算折扣的方法
public interface DiscoutStrategy
{
    // price: 原价,返回打折后的价格
    public decimal ApplyDiscount(decimal price);
}
// 具体折扣策略类1:原价出售
public class NoDiscountStrategy : DiscoutStrategy
{
    public decimal ApplyDiscount(decimal price)
    {
        return price;
    }
}
// 具体折扣策略类2:减去一定金额
public class FixedDiscountStrategy : DiscoutStrategy
{
    private decimal DiscountAmount;

    public FixedDiscountStrategy(decimal discountAmount)
    {
        DiscountAmount = discountAmount;
    }
    public decimal ApplyDiscount(decimal price)
    {
        return price - DiscountAmount;
    }
}
// 具体折扣策略类3:按比例打折
public class PercentageDiscountStrategy : DiscoutStrategy
{
    private decimal Percentage;
    public PercentageDiscountStrategy(decimal percentage)
    {
        Percentage = percentage;
    }
    public decimal ApplyDiscount(decimal price)
    {
        return price * Percentage;
    }
}
// 环境类,包含对折扣的引用以及计算折扣的方法
public class Product
{
    public string Name; // 产品名字
    public decimal Price;// 产品原价

    private DiscoutStrategy DiscoutStrategy; // 对折扣的引用

    public Product(string name, decimal price, DiscoutStrategy discoutStrategy)
    {
        Name = name;
        Price = price;
        DiscoutStrategy = discoutStrategy;
    }

    // 计算折扣的方法,实际上是调用的折扣属性进行计算
    public decimal CaculateDiscountPrice()
    {
        return DiscoutStrategy.ApplyDiscount(Price);
    }
}

4.策略模式的优点

  1. 算法的独立性:策略模式将不同的算法封装在各自的策略类中,使得算法与客户端代码相互独立。这样一来,可以单独修改、替换或扩展算法,而不会影响到使用算法的客户端代码。
  2. 可扩展性:由于策略模式使用了接口或抽象类定义策略,因此可以方便地新增其他实现策略,以满足新的需求。这种扩展性使得系统更具灵活性,能够适应变化和增长。
  3. 易于维护和测试:策略模式将不同的算法逻辑封装在各自的策略类中,使得代码结构清晰,易于理解和维护。此外,由于每个策略类都可以独立进行单元测试,因此可以更方便地对算法进行测试和验证。
  4. 动态切换算法:策略模式允许在运行时动态选择和切换算法,而不需要修改客户端代码。这种灵活性使得系统可以根据不同的情况或需求选择合适的算法,提高了系统的适应性和可定制性。
  5. 避免大量的条件语句:在没有策略模式的情况下,可能需要使用大量的条件语句来选择不同的算法。而策略模式通过将每个算法封装在独立的策略类中,避免了冗长的条件语句,使得代码更加简洁、可读性更高。

5.策略模式的应用

  1. 排序算法:不同的排序算法(如冒泡排序、快速排序、插入排序等)可以作为不同的策略实现,通过策略模式可以在运行时动态选择合适的排序算法。
  2. 文件压缩:不同的压缩算法(如ZIP、RAR、GZIP等)可以作为不同的策略实现,通过策略模式可以根据用户选择或文件类型选择合适的压缩算法。
  3. 日志记录:不同的日志记录策略(如控制台日志、文件日志、数据库日志等)可以作为不同的策略实现,通过策略模式可以动态选择日志记录方式。
  4. 图像处理:不同的图像处理算法(如旋转、裁剪、滤镜等)可以作为不同的策略实现,通过策略模式可以动态选择合适的图像处理算法。
  5. 游戏角色行为:在游戏中,不同的角色可能具有不同的行为方式(如攻击、防御、逃跑等),可以使用策略模式将每种行为封装为不同的策略类,并根据角色类型选择合适的行为策略。
  6. 网络请求策略:在网络请求的场景中,可以根据不同的网络环境或需求选择不同的请求策略,如同步请求、异步请求、缓存请求等。
  7. 优惠策略:在电商系统中,可以根据不同的促销活动或会员等级设置不同的优惠策略,通过策略模式可以动态选择适用的优惠策略。