2

我正在尝试编写一个可以同时接收集合和排序策略的排序方法。

我可以简单地收到一个 IComparer,但我更愿意枚举可能的排序策略。来电者必须从那里挑选他们的。

就像是:

public enum SortingStrategies { ByAgeDesc, ByAgeAsc, ByIncomeDesc, ByInconmeAsc };

其中每一个(ByAgeDesc、ByAgeAsc ...)都是 IComparer。

然后调用排序方法将是:

myObject.SortCollection(myCollection, SortingStrategies.ByIncomeDesc);

是否可以创建实例枚举?这是个好主意吗?

提前致谢!

4

5 回答 5

7

我不会为此使用直接枚举。我会创建一堆IComparer<T>可供选择的实现:

public static class SortingStrategy
{
    public static readonly IComparer<Person> ByAgeDescending = ...;
    public static readonly IComparer<Person> ByAgeAscending = ...;
    public static readonly IComparer<Person> ByIncomeDescending = ...;
    public static readonly IComparer<Person> ByIncomeAscending = ...;
}

...或者很可能使用组合来执行升序/降序部分(例如,通过扩展方法IComparer<T>创建一个反向包装器)。

当然,现在这不会强制调用者使用您的预定义值之一。您可以通过使用自己的类来强制它:

public abstract class SortingStrategy : IComparer<Person>
{
    public static readonly SortingStrategy ByAgeDescending = ...;
    public static readonly SortingStrategy ByAgeAscending = ...;
    public static readonly SortingStrategy ByIncomeDescending = ...;
    public static readonly SortingStrategy ByIncomeAscending = ...;

    private SortingStrategy() {}

    private class ByAgeStrategy : SortingStrategy { ... }
    private class ByIncomeStrategy : SortingStrategy { ... }
}

这里私有构造函数阻止任何其他子类,但私有嵌套类仍然可以对其进行子类化,因为它们可以访问构造函数。

然后,您可以使您的方法采用 aSortingStrategy而不仅仅是IComparer<T>.

当然,正如 James 所建议的,从长远来看,使用 LINQ 可能会更加灵活。这取决于你的目标是什么。

于 2012-08-13T12:02:43.060 回答
1

C# 不允许有任意数据类型的枚举(VB.NET 的那种,带有 hack)。但是您可以简单地将各个排序策略声明为static readonly您的类的字段SortingStrategies,并让它们实现IComparable

另一方面,您现在已经对排序策略进行了硬编码。在某些情况下这可能是完全可以接受的,但我会保持警惕,因为它不是完全可扩展的。

于 2012-08-13T12:02:24.923 回答
1

在这里,您最终会得到一个 switch 或 if 块,这在代码可重用性/可扩展性方面是丑陋的。在这里使用Strategy Pattern会好得多。

因此,对于策略模式的排序示例

using System;
using System.Collections.Generic;

namespace DoFactory.GangOfFour.Strategy.RealWorld
{
  /// <summary>
  /// MainApp startup class for Real-World 
  /// Strategy Design Pattern.
  /// </summary>
  class MainApp
  {

    /// <summary>
    /// Entry point into console application.
    /// </summary>
    static void Main()
    {
      // Two contexts following different strategies
      SortedList studentRecords = new SortedList();

      studentRecords.Add("Samual");
      studentRecords.Add("Jimmy");
      studentRecords.Add("Sandra");
      studentRecords.Add("Vivek");
      studentRecords.Add("Anna");

      studentRecords.SetSortStrategy(new QuickSort());
      studentRecords.Sort();

      studentRecords.SetSortStrategy(new ShellSort());
      studentRecords.Sort();

      studentRecords.SetSortStrategy(new MergeSort());
      studentRecords.Sort();

      // Wait for user
      Console.ReadKey();
    }
  }

  /// <summary>
  /// The 'Strategy' abstract class
  /// </summary>
  abstract class SortStrategy
  {
    public abstract void Sort(List<string> list);
  }

  /// <summary>
  /// A 'ConcreteStrategy' class
  /// </summary>
  class QuickSort : SortStrategy
  {
    public override void Sort(List<string> list)
    {
      list.Sort(); // Default is Quicksort
      Console.WriteLine("QuickSorted list ");
    }
  }

  /// <summary>
  /// A 'ConcreteStrategy' class
  /// </summary>
  class ShellSort : SortStrategy
  {
    public override void Sort(List<string> list)
    {
      //list.ShellSort(); not-implemented
      Console.WriteLine("ShellSorted list ");
    }
  }

  /// <summary>
  /// A 'ConcreteStrategy' class
  /// </summary>
  class MergeSort : SortStrategy
  {
    public override void Sort(List<string> list)
    {
      //list.MergeSort(); not-implemented
      Console.WriteLine("MergeSorted list ");
    }     
  }

  /// <summary>
  /// The 'Context' class
  /// </summary>
  class SortedList
  {
    private List<string> _list = new List<string>();
    private SortStrategy _sortstrategy;

    public void SetSortStrategy(SortStrategy sortstrategy)
    {
      this._sortstrategy = sortstrategy;
    }

    public void Add(string name)
    {
      _list.Add(name);
    }

    public void Sort()
    {
      _sortstrategy.Sort(_list);

      // Iterate over list and display results
      foreach (string name in _list)
        Console.WriteLine(" " + name);
      Console.WriteLine();
    }
  }
}

有关此模式的更多信息和上述代码的解释,请参见http://www.dofactory.com/Default.aspx

我希望这有帮助。

于 2012-08-13T12:09:44.607 回答
0

您可以轻松添加扩展方法(如果myObject是某种系统类型),例如

public static IEnumerable<MyObjectType>SortCollection(this MyObjectType myObject, SortingStrategies sotrStrategy) 
{
   ....
}

并像这样使用

MyObjectType myObject = new .... 
myObject.Sort(SortingStrategies.ByAgeDesc);

如果 where是非myObject系统类型,只需向您的类型添加一个新功能。

于 2012-08-13T12:02:49.743 回答
0

枚举值不能是IComparer. 但是,您可以创建一个静态类:

public static class SortingStrategies{

  static SortingStrategies() {
    ByAgeDesc = new ByAgeDescComparer();
    ByAgeAsc = new ByAgeAscComparer();
    ByIncomeDesc = new ByIncomeDescComparer()
  }

  public static IComparer ByAgeDesc { get; private set; }

  public static IComparer ByAgeAsc { get; private set; }

  public static IComparer ByIncomeDesc { get; private set; }

}

您可以像这样引用所需的IComparer

SortingStrategies.ByIncomeDesc
于 2012-08-13T12:03:39.537 回答