1.开始我们想要这样一个类Sorter, 通过里面的Sort方法可以将一个int数组排序,这里我们用选择排序来实现
1 int[] arr = { 9, 2, 3, 5, 7, 1, 4 }; 2 3 Sorter sorter = new Sorter(); 4 5 sorter.Sort(arr);
1 public class Sorter 2 { 3 public void Sort(int[] arr) 4 { 5 for (int i = 0; i < arr.Length - 1; i++) 6 { 7 int curr_pos = i; 8 9 for (int j = i + 1; j < arr.Length; j++) 10 { 11 if (arr[curr_pos] > arr[j]) 12 { 13 //交换下标 14 curr_pos = j; 15 16 } 17 } 18 19 //交换位置 20 ExchangeLocation(arr, curr_pos, i); 21 } 22 } 23 24 public static void ExchangeLocation(int[] arr, int a, int b) 25 { 26 int temp = arr[a]; 27 arr[a] = arr[b]; 28 arr[b] = temp; 29 } 30 31 32 }
2.接下来就要对方法扩展,如果我们想要对double 数组排序,想要对float数组排序呢?难道是再写两个方法吗?如果是对Cat类来排序呢?来看下面的Cat类
如果要比较Cat的大小必须提供一个比较方法
1 public class Cat 2 { 3 public int Weight { get; set; } 4 5 public int Height { get; set; } 6 7 public Cat(int weight,int height) 8 { 9 this.Weight = weight; 10 this.Height = height; 11 } 12 13 public int CompareTo(Cat c) 14 { 15 if (this.Weight < c.Weight) 16 return -1; 17 else if (this.Weight > c.Weight) 18 return 1; 19 else 20 return 0; 21 } 22 }
3.然后在Sorter里面添加排序猫的方法
1 public void SortCat(Cat[] arr) 2 { 3 for (int i = 0; i < arr.Length - 1; i++) 4 { 5 int curr_pos = i; 6 7 for (int j = i + 1; j < arr.Length; j++) 8 { 9 if (arr[curr_pos].CompareTo(arr[j])==1) 10 { 11 //交换下标 12 curr_pos = j; 13 14 } 15 } 16 17 //交换位置 18 ExchangeLocationCat(arr, curr_pos, i); 19 } 20 } 21 22 public static void ExchangeLocationCat(Cat[] arr, int a,int b) 23 { 24 Cat temp = arr[a]; 25 arr[a] = arr[b]; 26 arr[b] = temp; 27 }
4.那么如果要对狗,对车,对运动员进行排序呢?在上述Sorter 类中我们都写成固定的SortCat ,SortIntArray等等方法,没有一个通用的方法来实现排序,那么怎么能够抽象出一个通用的方法呢?
很容易想到的方法是将Sort方法的参数改成实现接口Comparable的数组,Comparable接口的有一个CompareTo方法,所有想要排序的数组的元素类型
必须要实现Comparable,也就是说狗,车,运动员如果想要排序,就必须实现Comparable接口,传入对应的排序规则CompareTo 代码改写如下:
1 public interface Comparable 2 { 3 int CompareTo(object o); 4 }
1 public void SortComparable(Comparable[] arr) 2 { 3 for (int i = 0; i < arr.Length - 1; i++) 4 { 5 int curr_pos = i; 6 7 for (int j = i + 1; j < arr.Length; j++) 8 { 9 if (arr[curr_pos].CompareTo(arr[j])==1) 10 { 11 //交换下标 12 curr_pos = j; 13 14 } 15 } 16 17 //交换位置 18 ExchangeLocationComparable(arr, curr_pos, i); 19 } 20 } 21 22 public static void ExchangeLocationComparable(Comparable[] arr, int a,int b) 23 { 24 Comparable temp = arr[a]; 25 arr[a] = arr[b]; 26 arr[b] = temp; 27 }
1 public class Cat: Comparable 2 { 3 public int Weight { get; set; } 4 5 public int Height { get; set; } 6 7 public Cat(int weight,int height) 8 { 9 this.Weight = weight; 10 this.Height = height; 11 } 12 13 //public override int CompareTo(Cat c) 14 //{ 15 // if (this.Weight < c.Weight) 16 // return -1; 17 // else if (this.Weight > c.Weight) 18 // return 1; 19 // else 20 // return 0; 21 //} 22 23 public override string ToString() 24 { 25 return $"catHeight:{this.Height},weight:{this.Weight}"; 26 } 27 28 public int CompareTo(object o) 29 { 30 Cat c = (Cat)o; 31 if (this.Weight < c.Weight) 32 return -1; 33 else if (this.Weight > c.Weight) 34 return 1; 35 else 36 return 0; 37 } 38 }
5.故事进行到这里看起来一切都很美好, 如果想要对一个类排序,那么就去实现Comparable 接口好了。但是事实却没有这么简单, 现在的需求变了:我们想在对猫进行排序的时候,不光想按
照体重对它排序,我们还想按照身高进行排序 ,如果以后对猫扩展其他属性的话,有可能会按照其他属性排序,那么该怎么办? 我的想法是传入规则,就是传入一个判断的方法,参数是一个方法,
排序的时候你想按照什么规则排序,你就传入那个规则的方法,我们可以定义一个比较器,参数同样是要比较的类和按照什么规则比较的方法:
1 public interface Comparator<T> 2 { 3 int Compare(T o1, T o2); 4 }
1 public class Cat 2 { 3 public int Weight { get; set; } 4 5 public int Height { get; set; } 6 7 public Cat(int weight,int height) 8 { 9 this.Weight = weight; 10 this.Height = height; 11 } 12 13 public override string ToString() 14 { 15 return $"catHeight:{this.Height},weight:{this.Weight}"; 16 } 17 18 }
1 public class Sorter<T> 2 { 3 4 public void Sort(T[] arr, Comparator<T> comparator) 5 { 6 for (int i = 0; i < arr.Length - 1; i++) 7 { 8 int curr_pos = i; 9 10 for (int j = i + 1; j < arr.Length; j++) 11 { 12 if (comparator.Compare(arr[curr_pos],arr[j])==1) 13 { 14 //交换下标 15 curr_pos = j; 16 17 } 18 } 19 20 //交换位置 21 ExchangeLocationComparable(arr, curr_pos, i); 22 } 23 } 24 25 public static void ExchangeLocationComparable(T[] arr, int a,int b) 26 { 27 T temp = arr[a]; 28 arr[a] = arr[b]; 29 arr[b] = temp; 30 } 31 32 }
1 public class CatHeightComparator : Comparator<Cat> 2 { 3 public int Compare(Cat o1, Cat o2) 4 { 5 if (o1.Height<o2.Height) 6 { 7 return -1; 8 } 9 else if (o1.Height == o2.Height) 10 { 11 return 0; 12 } 13 else 14 { 15 return 1; 16 } 17 } 18 }
调用
1 Cat[] arr = new Cat[] { new Cat(3, 3), new Cat(5, 5), new Cat(1, 1) }; 2 Sorter<Cat> sorter = new Sorter<Cat>(); 3 sorter.Sort(arr,new CatHeightComparator()); 4 5 PrintCat(arr); 6 7 Console.ReadKey();
6.这样一来可以看到,猫用不着实现Comparable了, 我们想按照猫的身高排序,只需写一个CatHeightComparator比较器,对体重排序就写一个CatWeightComparator,比较的规则
形成一个方法并当做参数传入,增加了Sort方法的灵活性,而且这种设计非常符合开闭原则
7.总结:策略模式的关键词是策略,在这片文章中我定义它为规则, 什么情况下需要使用策略模式呢? 比如我们计算员工月工资,计算会员的月积分,都需要有一个计算公式,每一个员工
都有可能又不一样的计算规则,每一个会员根据等级也可能会有不同的计算方式,在多数简单的场景下,我们习惯使用if else 或者switch 等等分支语句,但是当规则复杂到一定程度时
而且有可能发生频繁变化时,我们应该尝试使用一些策略模式的思想来完成
注意我上面的发生频繁变化,如果业务基本不会发生变化时,我们使用设计模式时就要做出权衡,但是话又说回来,我们怎么知道这块业务不会发生变化呢?所以我们应该在写代码的时候就
需要判断哪里有可能发生变化,使用一些设计模式,在代码需要重构的时候,我们也应该想到使用设计模式来帮助我们解决相关问题