65.9K
CodeProject 正在变化。 阅读更多。
Home

策略模式-C#

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (23投票s)

2014年5月23日

CPOL

3分钟阅读

viewsIcon

116548

使用 C# 解释策略模式

引言

策略模式可以归类为行为设计模式,也是我最喜欢的模式之一,因为它简单而强大。当你的对象需要执行一个通用的操作,并且有多种选项可供选择时,可以考虑使用它。

背景

让我们理解一下策略模式的广泛接受的定义,你可以在网上找到各种资源。“策略模式定义了一系列算法,并将每一个算法封装起来,使它们可以互相替换。” 觉得定义很困惑?让我们尝试将其分解为三个部分:-

1) 算法族 - 该定义表示该模式定义了一个算法族 - 这意味着我们有一些功能(在这些算法中)将为我们的对象执行相同的通用操作,但以不同的方式进行。

2) 封装每一个算法 - 该模式将迫使你将算法放在不同的类中(封装它们)。这样做可以帮助我们为对象选择合适的算法。

3) 使它们可以互相替换 - 策略模式的优点在于我们可以运行时选择应该应用于对象的算法,并且可以互相替换它们

使用代码

让我们看一个使用策略模式的例子,这将使一切都变得清晰。假设你必须编写一个应用程序,可以对不同类型的对象进行排序,这意味着它可以对大学中学生的学号、铁路乘客的车票号码,甚至更多,可以对居住在一个县的所有人的姓名进行排序。

这个问题似乎非常简单,并且对于所有这些都只涉及一件事,即排序。现在,让我们试着回忆一下我们上学的时候,教授们教我们算法设计。我们被告知,不同排序算法的复杂性是一个相对的术语 - 意味着它基于要排序的元素的数量和类型。不再赘述算法科学,假设我们已经制定了(无论是正确还是错误的)快速排序将非常适合对县居民的姓名进行排序,归并排序将适合于学号(整数/双精度),而堆排序将最适合于对铁路乘客进行排序。这是我们可以应用策略模式的最佳场景。我们将封装我们所有的算法,并在运行时选择我们将使用哪一个。看看下面的代码(用C#编写,可以以类似的方式应用于任何支持面向对象编程的语言),它会告诉你我们是如何实现策略的。

class Program
{
   static void Main(string[] args)
   {
      ISortingStrategy sortingStrategy = null;

      //Sorting the countyResidents
      List<string> countyResidents = new List<string>{ "ad","ac", "ax", "zw" };
      sortingStrategy = GetSortingOption(ObjectToSort.CountyResidents);
      sortingStrategy.Sort(countyResidents);

      //Sorting student numbers

      List<int> studentNumbers = new List<int>{ 123,678,543,  189};
      sortingStrategy = GetSortingOption(ObjectToSort.StudentNumber);
      sortingStrategy.Sort(studentNumbers);
      
      
      //Sorting railway passengers      
      List<string> railwayPassengers = new List<string> { "A21", "Z2", "F3", "G43" };
      sortingStrategy = GetSortingOption(ObjectToSort.RailwayPassengers);
      sortingStrategy.Sort(railwayPassengers);

    }

   private static ISortingStrategy GetSortingOption(ObjectToSort objectToSort)
   {
      ISortingStrategy sortingStrategy = null;

      switch (objectToSort)
      {
         case ObjectToSort.StudentNumber:
              sortingStrategy = new MergeSort();              
              break;
         case ObjectToSort.RailwayPassengers:
              sortingStrategy = new HeapSort();
              break;
         case ObjectToSort.CountyResidents:
              sortingStrategy = new QuickSort();
              break;
         default:
                    break;
      }
      return sortingStrategy;
   }
}
 

// 不同类型的排序的枚举。

public enum ObjectToSort
{
   StudentNumber,
   RailwayPassengers,
   CountyResidents
}

// 排序策略的接口。

public interface ISortingStrategy 
{
   void Sort<T>(List<T> dataToBeSorted);
}

// 算法 - 快速排序。

public class QuickSort : ISortingStrategy
{
   #region ISortingStrategy Members
      public void Sort<T>(List<T> dataToBeSorted)
      {
        //Logic for quick sort
      }
   #endregion
}

// 算法 - 归并排序。

public class MergeSort : ISortingStrategy
{
   #region ISortingStrategy Members
      public void Sort<T>(List<T> dataToBeSorted)
      {
         //Logic for Merge sort
      }
   #endregion
}

// 算法 - 堆排序。

public class HeapSort : ISortingStrategy
{
   #region ISortingStrategy Members
      public void Sort<T>(List<T> dataToBeSorted)
      {
         //Logic for Heap sort
      }
   #endregion
}

多么美妙!我们的ISortingStrategy对象将决定调用哪个算法。最棒的是,假设我们意识到我们的一个算法存在缺陷,我们只需要更改GetSortingOption方法中的排序算法引用,这样我们就不需要在客户端代码(即Program类)中更改任何内容。我们甚至可以在运行时决定算法。假设在高峰时段,当铁路乘客数量增加时,我们可以使用另一个定制算法(例如HugeDataSorting)。根据乘客的数量,ISortingStrategy对象将不断更改对HeapSort或HugeDataSorting的引用。

关注点

学习了策略模式后,请考虑将其应用于你觉得你的对象需要执行类似操作的地方,但是该操作的执行方式存在差异。用另一个实际的例子来结束本文。考虑将此模式应用于折扣系统,该系统计算不同客户的折扣。因此,该系统将在运行时决定调用哪种折扣方法,具体取决于客户类型。

历史

版本 1- (2014/05/23)
© . All rights reserved.