策略模式

简介

策略模式(Strategy Pattern)是一种行为设计模式,它允许在运行时选择算法的行为。这种模式定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式使得算法可以独立于其使用者而变化,使得使用者可以根据需要在运行时选择适当的算法。

以下是策略模式的一般结构和示例代码:

结构

  • Context(上下文):维持一个对Strategy对象的引用,并且可以调用Strategy定义的算法。
  • Strategy(策略):定义所有支持的算法的公共接口。
  • ConcreteStrategy(具体策略):实现Strategy接口的具体算法。

案例

使用策略模式来处理购物车结账支付的情景。

using System;

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

// 具体策略1:信用卡支付
class CreditCardPayment : IPaymentStrategy
{
    private string cardNumber;
    private string expiryDate;
    private string cvv;

    public CreditCardPayment(string cardNumber, string expiryDate, string cvv)
    {
        this.cardNumber = cardNumber;
        this.expiryDate = expiryDate;
        this.cvv = cvv;
    }

    public void Pay(double amount)
    {
        Console.WriteLine($"{amount} paid with Credit Card");
    }
}

// 具体策略2:支付宝支付
class AlipayPayment : IPaymentStrategy
{
    private string email;
    private string password;

    public AlipayPayment(string email, string password)
    {
        this.email = email;
        this.password = password;
    }

    public void Pay(double amount)
    {
        Console.WriteLine($"{amount} paid with Alipay");
    }
}

// 上下文
class ShoppingCart
{
    private IPaymentStrategy paymentStrategy;

    public void SetPaymentStrategy(IPaymentStrategy paymentStrategy)
    {
        this.paymentStrategy = paymentStrategy;
    }

    public void Checkout(double amount)
    {
        paymentStrategy.Pay(amount);
    }
}

// 使用策略模式进行支付
class Program
{
    static void Main(string[] args)
    {
        ShoppingCart cart = new ShoppingCart();

        // 选择支付宝支付
        cart.SetPaymentStrategy(new AlipayPayment("example@example.com", "password123"));
        cart.Checkout(100);

        // 选择信用卡支付
        cart.SetPaymentStrategy(new CreditCardPayment("1234567890123456", "12/24", "123"));
        cart.Checkout(200);
    }
}

在这个示例中,IPaymentStrategy是支付策略接口,CreditCardPaymentAlipayPayment是具体的支付策略类。ShoppingCart是上下文类,它具有一个IPaymentStrategy类型的成员变量。在Main方法中,我们可以看到具体的策略选择发生在设置支付策略时,并通过调用Checkout方法来实现结账操作。

其他案例

  1. 商业规则引擎: 在许多企业应用程序中,存在大量的业务规则需要动态应用。通过使用策略模式,可以将不同的业务规则封装在不同的策略类中,并在运行时根据需要选择适当的策略。这样可以实现业务规则的动态管理和扩展。

  2. 排序算法: 在.NET中,List<T> 提供了 Sort 方法用于对列表进行排序。这个方法接受一个实现了 IComparer<T> 接口的对象作为参数,该对象定义了排序的算法。可以根据需要选择不同的排序算法,例如冒泡排序、快速排序等,从而实现不同的排序策略。

  3. 数据压缩和解压缩: 在处理文件或网络传输中,常常需要对数据进行压缩和解压缩。通过策略模式,可以将不同的压缩和解压缩算法封装在不同的策略类中,然后在运行时选择适当的策略。

优点

  1. 可替换性: 策略模式允许在运行时动态选择算法,因此可以轻松地替换算法或策略,而无需修改上下文。

  2. 代码复用: 策略模式通过将每个算法封装在单独的策略类中,可以促进代码的重用,因为同样的算法可以在不同的上下文中使用。

  3. 易于扩展: 新的策略可以很容易地添加到系统中,而不会影响现有的代码。这种扩展性使得系统更容易适应变化和新需求。

  4. 单一职责原则: 策略模式将不同的算法分离到独立的策略类中,符合单一职责原则,使得每个类都专注于一个特定的任务。

  5. 降低耦合度: 上下文类与具体的策略类之间的耦合程度较低,因为它们之间通过接口进行交互,从而使得系统更加灵活和可维护。

缺点

  1. 类数量增加: 使用策略模式会导致系统中策略类的数量增加,特别是当有大量的算法需要支持时,可能会导致类的膨胀。

  2. 客户端必须知道所有的策略: 客户端必须知道所有可用的策略并选择合适的策略。这可能会增加客户端的复杂性,特别是当策略数量较多时。

  3. 上下文与策略的耦合度: 尽管上下文与具体策略类之间的耦合程度较低,但上下文仍然必须知道所有可能的策略,并且必须能够选择正确的策略。这可能会导致一定程度的耦合。

  4. 运行时性能开销: 在运行时动态选择策略可能会增加一些性能开销,尤其是在频繁切换策略时。

适用场景

  1. 需要在运行时动态选择算法: 当程序需要根据不同的情况选择不同的算法或策略时,策略模式是一个很好的选择。例如,根据用户的偏好选择不同的排序算法,或根据环境条件选择不同的数据压缩算法。

  2. 存在多个相关的类,它们的行为仅在某些情况下有所不同: 如果有一组相关的类,它们的行为在某些情况下有所不同,但是可以抽象出共同的接口,那么策略模式是一个很好的解决方案。通过将不同的行为封装在策略类中,可以减少重复代码,提高代码的可维护性和可复用性。

  3. 需要动态切换行为: 当需要在运行时动态切换对象的行为时,策略模式是一种很好的实现方式。例如,在游戏中根据不同的游戏关卡选择不同的敌人AI行为。

  4. 不希望暴露复杂的条件逻辑: 如果存在复杂的条件逻辑,但不希望将其暴露给客户端,那么可以使用策略模式来封装这些逻辑。通过将不同的条件逻辑封装在不同的策略类中,可以使客户端代码保持简洁和易于理解。

  5. 需要避免使用大量的条件语句: 当存在大量的条件语句,并且这些条件语句随着需求的变化而频繁改变时,可以考虑使用策略模式来避免条件语句的过度复杂化。策略模式将每个条件分支封装在单独的策略类中,使得代码更加清晰和易于维护。

posted @ 2024-02-29 14:33  咸鱼翻身?  阅读(5)  评论(0编辑  收藏  举报