编程时遇到排序在平常不过使用Net最常见的就是对泛型List<T>进行排序如果T是简单数据类型排序那么很简单直接调用List的Sort()方法就可以了但是如果我们要排的对象复杂了怎么办我们知道List<T> sort()最后是用快速排序实现快速排序也好什么排序都需要知道list中item之间的比较结果如果是简单的int类型直接判断即可对实现了IComparable接口的对象可以调用其CompareTo()实现item比较大小下面是一个快速排序的写法 void Sort<T>(T[] array int left int right IComparer_sly<T> comparer) where T : IComparable { if (left < right) { T middle = array[(left + right) / ]; int i = left ; int j = right + ; while (true) { while (array[++i]CompareTo(middle) < ) ; while (array[j]CompareTo(middle) > ) ; if (i >= j) break; T temp = array[i]; array[i] = array[j]; array[j] = temp; } Sort(array left i comparer); Sort(array j + right comparer); } } 问题 对于前两种情况固然可以实现排序但是我们不可能要求所有待排序的对象都实现IComparable接口就算能够保证每个对象都实现IComparable接口如果想实现对象内多个字段排序比如Student对象有时候想按照姓名排序有时候是成绩有时候是年龄这怎么破 按照面向对象的思想要把变化独立出来封装变化对于我们排序List<T>时变化的其实就是怎么比较两个对象的大小的算法如果我们可以把这个算法拿出来排序就简单了很多无论什么排序算法都是由的我们要封装的部分是怎样比较两个item的大小的算法为了实现拓展性我们要遵循面向对象设计的另外一个重要原则针对接口编程而不是针对实现编程 编写通用的List<T>排序方法首先定义一个接口里面有一个比较item大小的方法在排序的时候作为参数传入当然是传入它的实现类有了这个想法我们可以自己写个List<T>的排序方法 public interface IComparer_sly<T>{ int Compare(T x T y); } 然后为了测试我们为List<T>加一个包装写一个自己的Sort方法内部也用快速排序实现一直困惑我们的变化部分——比较大小算法我们把它封转起来作为参数传入 using System; using SystemCollectionsGeneric; namespace TestStategy {public class ListTest<T> { public List<T> list = new List<T>(); public void Sort(IComparer_sly<T> comparer) { T[] array = listToArray(); int left = ; int right = arrayLength ; QuickSort(array left right comparer); list = new List<T>(array); } private void QuickSort<S>(S[] array int left int right IComparer_sly<S> comparer) { if (left < right) { S middle = array[(left + right) / ]; int i = left ; int j = right + ; while (true) { while (comparerCompare(array[++i] middle) < ) ; while (comparerCompare(array[j] middle) > ) ; if (i >= j) break; S temp = array[i]; array[i] = array[j]; array[j] = temp; } QuickSort(array left i comparer); QuickSort(array j + right comparer); } } } }比如现在我们有个Student 的实体 public class Student { public Student(int id string name) { thisID = id; thisName = name; } public int ID { get; set; } public string Name { get; set; } } 如果想对这个实体组成的List<T>进行排序我们只需一个实现 IComparer_sly<Student>的类 StudentComparer并在内部实现其比较大小方法——Compare()同时我们可以添加递增还是递减排序的控制 class StudentComparer : IComparer_sly<Student> { private string expression; private bool isAscending; public StudentComparer(string expression bool isAscending) { thisexpression = expression; thisisAscending = isAscending; } public int Compare(Student x Student y) { object v = GetValue(x) v = GetValue(y); if (v is string || v is string) { string s = ((v == null) ? : vToString()Trim()); string s = ((v == null) ? : vToString()Trim()); if (sLength == && sLength == ) return ; else if (sLength == ) return ; else if (sLength == ) return ; } // 这里就偷懒调用系统方法不自己实现了其实就是比较两个任意相同类型数据大小自己实现比较麻烦 if (!isAscending) return ComparerDefaultCompare(v v); return ComparerDefaultCompare(v v); } private object GetValue(Student stu) { object v = null; switch (expression) { case id: v = stuID; break; case name: v = stuName; break; default: v = null; break; } return v; } }测试一下好不好使 static void Main(string[] args) { ListTest<Student> test = new ListTest<Student>(); for (int i = ; i < ; i++) { Student stu = new Student(istringFormat(N_+(i))); testlistAdd(stu); } ConsoleWriteLine(元数据); for (int i = ; i < testlistCount;i++ ) { ConsoleWriteLine(stringFormat(ID:{} Name:{} testlist[i]ID testlist[i]Name)); } ConsoleWriteLine(Name 递增); testSort(new StudentComparer(name true)); for (int i = ; i < testlistCount; i++) { ConsoleWriteLine(stringFormat(ID:{} Name:{} testlist[i]ID testlist[i]Name)); } }看看效果 NET List的sort如何为我们排序用ILSpy反编译可以看到在调用List<T>的sort()方法时内部调用的时 thisSort( thisCount null); 然后往里面扒经过一系列异常处理后会调用 ArraySort<T>(this_items index count comparer); this_items是把List内容转换成数组同样再经历一些列异常处理调用方法 ArraySortHelper<T>DefaultSort(array index length comparer); 再往里就和我们上面写的方法大同小异了只不过微软加了很多异常处理和算法优化 策略模式看清楚了上面这个例子我们就可以进入正题说说我们的策略模式了策略模式定义了一系列的算法并将每一个算法封装起来而且使它们还可以相互替换策略模式让算法独立于使用它的客户而独立变化(原文The Strategy Pattern defines a family of algorithmsencapsulates each oneand makes them interchangeable Strategy lets the algorithm vary independently from clients that use it) 这个模式涉及到三个角色 ;环境(Context)角色持有一个Strategy类的引用 ;抽象策略(Strategy)角色这是一个抽象角色通常由一个接口或抽象类实现此角色给出所有的具体策略类所需的接口 ;具体策略(ConcreteStrategy)角色包装了相关的算法或行为 相信大家可以分方便的把我们上面例子中的类对应上策略模式的角色IComparer接口是我们的抽象策略角色 ListTest<T> 类持有抽象策略的引用是环境(在Sort方法中其实可以把接口定义为类的属性在构造函数中赋值不过不适合此场景毕竟并不是所有List都需要排序不能强制其接受一个可能会用不到的接口当然对每个实例都需要用某个策略的场景是合适的)毫无疑问我们实现IComparer抽象策略的类就是具体策略 |