策略模式-C#






4.90/5 (23投票s)
使用 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的引用。