• 设计模式-策略模式


    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 等等分支语句,但是当规则复杂到一定程度时

    而且有可能发生频繁变化时,我们应该尝试使用一些策略模式的思想来完成

    注意我上面的发生频繁变化,如果业务基本不会发生变化时,我们使用设计模式时就要做出权衡,但是话又说回来,我们怎么知道这块业务不会发生变化呢?所以我们应该在写代码的时候就

    需要判断哪里有可能发生变化,使用一些设计模式,在代码需要重构的时候,我们也应该想到使用设计模式来帮助我们解决相关问题

  • 相关阅读:
    Java finally语句到底是在return之前还是之后执行?
    RedirectAttributes
    ueditor的使用
    controller跳到另一个controller
    $.post()用法例子
    进入一个jsp直接跳到另一个jsp
    mybatis多表查询
    asp.net在网页上显示数据库中的数据
    asp.net全局记住值
    面向对象
  • 原文地址:https://www.cnblogs.com/Spinoza/p/13881170.html
Copyright © 2020-2023  润新知