C#设计模式--策略模式(Strategy Pattern)

策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。在策略模式定义了一系列算法或策略,并将每个算法封装在独立的类中,使得它们可以互相替换。通过使用策略模式,可以在运行时根据需要选择不同的算法,而不需要修改客户端代码。

主要解决的问题

解决在多种相似算法存在时,使用条件语句(如if...else)导致的复杂性和难以维护的问题。

1. 定义策略接口

csharp 复制代码
public interface IStrategy
{
    void Execute();
}

2. 实现具体策略

csharp 复制代码
public class ConcreteStrategyA : IStrategy
{
    public void Execute()
    {
        Console.WriteLine("Executing strategy A");
    }
}

public class ConcreteStrategyB : IStrategy
{
    public void Execute()
    {
        Console.WriteLine("Executing strategy B");
    }
}

3. 上下文类

csharp 复制代码
public class Context
{
    private IStrategy _strategy;

    public Context(IStrategy strategy)
    {
        _strategy = strategy;
    }

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

    public void ExecuteStrategy()
    {
        _strategy.Execute();
    }
}

类图

IStrategy +void Execute() ConcreteStrategyA +void Execute() ConcreteStrategyB +void Execute() Context -IStrategy _strategy +Context(IStrategy strategy) +void SetStrategy(IStrategy strategy) +void ExecuteStrategy()

用途

策略模式主要用于以下场景:

• 算法变化:当一个类的行为或其算法需要在运行时动态改变时。

• 多个算法变体:当有多个算法变体,并且需要在运行时选择其中一个时。

• 解耦:将算法的定义与使用算法的客户端解耦。

优点

  1. 灵活性:可以在运行时动态切换算法。
  2. 扩展性:增加新的策略非常容易,只需实现策略接口即可。
  3. 解耦:策略类和上下文类之间松耦合,符合开闭原则。

缺点

  1. 客户端复杂度:客户端必须了解所有策略类的区别,以便选择合适的策略。
  2. 增加对象数量:每个策略都是一个类,可能会导致类的数量增加。

实际开发中的应用举例

示例1:订单处理系统中的促销策略

假设一个订单处理系统,需要根据不同的促销策略,比如:没折扣、打折扣。也可以用是会员积分兑换,来计算订单的最终价格。

1. 定义促销策略接口

csharp 复制代码
public interface IPromotionStrategy
{
    decimal ApplyPromotion(decimal originalPrice);
}

2. 实现具体的促销策略

csharp 复制代码
public class NoDiscountStrategy : IPromotionStrategy
{
    public decimal ApplyPromotion(decimal originalPrice)
    {
        return originalPrice; // 没有折扣
    }
}

public class PercentageDiscountStrategy : IPromotionStrategy
{
    private readonly decimal _discountPercentage;

    public PercentageDiscountStrategy(decimal discountPercentage)
    {
        _discountPercentage = discountPercentage;
    }

    public decimal ApplyPromotion(decimal originalPrice)
    {
        return originalPrice * (1 - _discountPercentage / 100);//折扣
    }
}

public class FixedAmountDiscountStrategy : IPromotionStrategy
{
    private readonly decimal _discountAmount;

    public FixedAmountDiscountStrategy(decimal discountAmount)
    {
        _discountAmount = discountAmount;
    }

    public decimal ApplyPromotion(decimal originalPrice)
    {
        return originalPrice - _discountAmount;
    }
}

3. 上下文类

csharp 复制代码
public class Order
{
    private IPromotionStrategy _promotionStrategy;
    private decimal _originalPrice;

    public Order(decimal originalPrice, IPromotionStrategy promotionStrategy)
    {
        _originalPrice = originalPrice;
        _promotionStrategy = promotionStrategy;
    }

    public void SetPromotionStrategy(IPromotionStrategy promotionStrategy)
    {
        _promotionStrategy = promotionStrategy;
    }

    public decimal CalculateFinalPrice()
    {
        return _promotionStrategy.ApplyPromotion(_originalPrice);
    }
}

4. 使用示例

csharp 复制代码
class Program
{
    static void Main(string[] args)
    {
        // 创建订单,初始价格为100元,没有折扣
        var order = new Order(100, new NoDiscountStrategy());
        Console.WriteLine($"Original price: {order.CalculateFinalPrice()}");

        // 应用百分比折扣策略,折扣10%
        order.SetPromotionStrategy(new PercentageDiscountStrategy(10));
        Console.WriteLine($"Price after 10% discount: {order.CalculateFinalPrice()}");

        // 应用固定金额折扣策略,折扣20元
        order.SetPromotionStrategy(new FixedAmountDiscountStrategy(20));
        Console.WriteLine($"Price after fixed 20 discount: {order.CalculateFinalPrice()}");
    }
}

类图:

IPromotionStrategy +decimal ApplyPromotion(decimal originalPrice) NoDiscountStrategy +decimal ApplyPromotion(decimal originalPrice) PercentageDiscountStrategy -decimal _discountPercentage +PercentageDiscountStrategy(decimal discountPercentage) +decimal ApplyPromotion(decimal originalPrice) FixedAmountDiscountStrategy -decimal _discountAmount +FixedAmountDiscountStrategy(decimal discountAmount) +decimal ApplyPromotion(decimal originalPrice) Order -IPromotionStrategy _promotionStrategy -decimal _originalPrice +Order(decimal originalPrice, IPromotionStrategy promotionStrategy) +void SetPromotionStrategy(IPromotionStrategy promotionStrategy) +decimal CalculateFinalPrice()

解释

  1. 定义促销策略接口:IPromotionStrategy 接口定义了一个 ApplyPromotion 方法,用于计算应用促销后的价格。
  2. 实现具体的促销策略:
    • NoDiscountStrategy:不应用任何折扣。
    • PercentageDiscountStrategy:应用百分比折扣。
    • FixedAmountDiscountStrategy:应用固定金额折扣。
  3. 上下文类:Order 类包含一个促销策略,并提供方法来设置促销策略和计算最终价格。
  4. 使用示例:创建一个订单,初始价格为100元,然后依次应用不同的促销策略,输出最终价格。

示例2:物流管理系统中的运输策略

假设一个物流管理系统,需要根据不同的运输方式(如快递、货运、空运等)来计算运费。也可以使用策略模式来实现这一点。

1. 定义运输策略接口

csharp 复制代码
public interface ITransportStrategy
{
    decimal CalculateShippingCost(decimal weight, decimal distance);
}

2. 实现具体的运输策略

csharp 复制代码
public class ExpressShippingStrategy : ITransportStrategy
{
    public decimal CalculateShippingCost(decimal weight, decimal distance)
    {
        // 快递费用计算公式:重量 * 距离 * 0.5
        return weight * distance * 0.5m;
    }
}

public class FreightShippingStrategy : ITransportStrategy
{
    public decimal CalculateShippingCost(decimal weight, decimal distance)
    {
        // 货运费用计算公式:重量 * 距离 * 0.3
        return weight * distance * 0.3m;
    }
}

public class AirShippingStrategy : ITransportStrategy
{
    public decimal CalculateShippingCost(decimal weight, decimal distance)
    {
        // 空运费用计算公式:重量 * 距离 * 1.0
        return weight * distance * 1.0m;
    }
}

3. 上下文类

csharp 复制代码
public class Shipment
{
    private ITransportStrategy _transportStrategy;
    private decimal _weight;
    private decimal _distance;

    public Shipment(decimal weight, decimal distance, ITransportStrategy transportStrategy)
    {
        _weight = weight;
        _distance = distance;
        _transportStrategy = transportStrategy;
    }

    public void SetTransportStrategy(ITransportStrategy transportStrategy)
    {
        _transportStrategy = transportStrategy;
    }

    public decimal CalculateTotalCost()
    {
        return _transportStrategy.CalculateShippingCost(_weight, _distance);
    }
}

4. 使用示例

csharp 复制代码
class Program
{
    static void Main(string[] args)
    {
        // 创建一个货物,重量为100公斤,距离为500公里,使用快递运输
        var shipment = new Shipment(100, 500, new ExpressShippingStrategy());
        Console.WriteLine($"Express Shipping Cost: {shipment.CalculateTotalCost()}");

        // 更改为货运运输
        shipment.SetTransportStrategy(new FreightShippingStrategy());
        Console.WriteLine($"Freight Shipping Cost: {shipment.CalculateTotalCost()}");

        // 更改为空运运输
        shipment.SetTransportStrategy(new AirShippingStrategy());
        Console.WriteLine($"Air Shipping Cost: {shipment.CalculateTotalCost()}");
    }
}

类图:

ITransportStrategy +decimal CalculateShippingCost(decimal weight, decimal distance) ExpressShippingStrategy +decimal CalculateShippingCost(decimal weight, decimal distance) FreightShippingStrategy +decimal CalculateShippingCost(decimal weight, decimal distance) AirShippingStrategy +decimal CalculateShippingCost(decimal weight, decimal distance) Shipment -ITransportStrategy _transportStrategy -decimal _weight -decimal _distance +Shipment(decimal weight, decimal distance, ITransportStrategy transportStrategy) +void SetTransportStrategy(ITransportStrategy transportStrategy) +decimal CalculateTotalCost()

解释

  1. 定义运输策略接口:ITransportStrategy 接口定义了一个 CalculateShippingCost 方法,用于计算运输费用。
  2. 实现具体的运输策略:
    • ExpressShippingStrategy:快递运输费用计算。
    • FreightShippingStrategy:货运运输费用计算。
    • AirShippingStrategy:空运运输费用计算。
  3. 上下文类:Shipment 类包含一个运输策略,并提供方法来设置运输策略和计算总费用。
  4. 使用示例:创建一个货物,初始运输方式为快递,然后依次更改为货运和空运,输出每种运输方式的费用。

优点

  1. 灵活性:可以在运行时动态切换促销策略。
  2. 扩展性:增加新的促销策略非常容易,只需实现 IPromotionStrategy 接口即可。
  3. 解耦:订单类和促销策略类之间松耦合,符合开闭原则。

缺点

  1. 客户端复杂度:客户端必须了解所有促销策略的区别,以便选择合适的策略。
  2. 增加对象数量:每个促销策略都是一个类,可能会导致类的数量增加。
相关推荐
千千寰宇17 分钟前
[设计模式/Java/多线程] 设计模式之单例模式【9】
设计模式·操作系统-进程/线程/并发
此木|西贝7 小时前
【设计模式】原型模式
java·设计模式·原型模式
“抚琴”的人7 小时前
【机械视觉】C#+VisionPro联合编程———【六、visionPro连接工业相机设备】
c#·工业相机·visionpro·机械视觉
FAREWELL000759 小时前
C#核心学习(七)面向对象--封装(6)C#中的拓展方法与运算符重载: 让代码更“聪明”的魔法
学习·c#·面向对象·运算符重载·oop·拓展方法
CodeCraft Studio9 小时前
Excel处理控件Spire.XLS系列教程:C# 合并、或取消合并 Excel 单元格
前端·c#·excel
勘察加熊人11 小时前
forms实现连连看
c#
hvinsion11 小时前
PPT助手:一款集计时、远程控制与多屏切换于一身的PPT辅助工具
c#·powerpoint·ppt·ppt助手·ppt翻页
振鹏Dong11 小时前
策略模式——本质是通过Context类来作为中心控制单元,对不同的策略进行调度分配。
java·策略模式
weixin_3077791312 小时前
使用C#实现从Hive的CREATE TABLE语句中提取分区字段名和数据类型
开发语言·数据仓库·hive·c#
时光追逐者13 小时前
在 Blazor 中使用 Chart.js 快速创建数据可视化图表
开发语言·javascript·信息可视化·c#·.net·blazor