关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

带你读《2022技术人的百宝黑皮书》——浅析设计模式2 —— 策略模式(3)

发布时间:2023-06-28 18:00:36

带你读《2022技术人的百宝黑皮书》——浅析设计模式2 —— 策略模式(2)

https://developer.leiyu.cn/article/1262320?groupCode=taobaotech



与简单工厂模式的区别


从上面的代码示例及类图可以看出来,策略模式和上一篇文章中介绍的简单工厂模式很像,两者主要区别在于 Context 类和工厂类。为了方便对比,我们把这两个类的代码单独拎出来看看:

public class Context_TaoPlatform{  //持有抽象策略的引用  private Strategy myStrategy;  //生成构造方法,让平台根据传入的策略参数选择促销活动  public TaoPlatform(Strategy strategyType) {  this.myStrategy = strategyType;  }  //向用户展示促销活动  public void taoPlatformShow(String time) {  System.out.println(time + "的促销策略是:");  myStrategy.show();  } }

     

public class Factory{  public static Shirt exhibit(String ShirtName){  switch(ShirtName){  case "女款衬衫":  return new WomenShirt();  case "男款衬衫":  return new MenShirt();  default:  return null;  }  } }

   


首先看一下接收参数:工厂类 Factory 中的 exhibit() 方法接收字符串,返回一个 Shirt 对象;

环境类 Context_TaoPlatform 初始化时需要接收一个 Strategy 对象。也就是说:工厂类中是根据接收的条件创建一个相应的对 象,而 Context 类接收的是一个对象,可以调用方法去执行此对象的方法。


举个例子:笔有很多种,假设有一个工厂专门负责生产不同用途的笔。

1.工厂模式:根据用户给出的目的来生产不同用途的笔,如:要写毛笔字就生产毛笔、要写钢笔字就生产钢笔。即 根据用户给出的某种属性,生产能做出相应行为的一种对象返回给用户,重点在于创建何种对象。

2.策略模式:用工厂生产的笔去出做对应的行为,如:用毛笔写毛笔字、用钢笔写钢笔字。即根据用户给出的某种 对象,执行相应的方法,重点在于选择何种行为。


JDK源码赏析


这里以 Comparator 比较器为例,通过分析其源码实现来深入理策略模式。


在 JDK 中,我们调用数组工具类 Arrays 的一个排序方法 sort() 时,可以使用默认的排序规则(升序),也可以自 定义一种排序的规则,即自定义实现升序或降序的排序。源码如下:

public class Arrays{  public staticvoid sort(T[] a, Comparator c) {  if (c == null) {  //若没有传入Comparator接口的实现类对象,调用默认的升序排序方法  sort(a);  } else {  if (LegacyMergeSort.userRequested)  //jdk5及之前的传统归并排序,新版本中LegacyMergeSort.userRequested默认false  legacyMergeSort(a, c);  else  //改进后的归并排序  TimSort.sort(a, 0, a.length, c, null, 0, 0);  }  } }

   


此时我们需要传入两个参数:一个是待排序的数组,另一个则是 Comparator 接口的实现类对象。其中,Comparator 接口是一种函数式接口,该接口中定义了一个抽象方法 int compare(T o1, T o2),用于定义具体的排序规 则。这里,Comparator 接口就是策略模式中的抽象策略接口,它定义了一个排序算法,而具体策略(具体的排序 算法)将由用户来定义,那么Arrays 就是一个环境类,sort() 方法可以传入一个策略 c ,让 Arrays 根据这个策略 进行排序任务。

public class demo {  public static void main(String[] args) {   Integer[] data = {2, 0, 22, 14, 1, 3, 4};  // 实现降序排序  Arrays.sort(data, new Comparator() {  // 排序策略 降序  public int compare(Integer o1, Integer o2) {  return o2 - o1;  }  });  System.out.println(Arrays.toString(data));  } }

   


在上面这个 demo 中,我们在调用 Arrays.sort() 方法时,第二个参数传递的是 Comparator 接口的子实现类对 象。由此可见,Comparator充当的是抽象策略角色,而具体的子实现类充当的是具体策略角色,环境角色类 Arrays 应该持有抽象策略的引用来调用。那么,Arrays.sort() 方法究竟有没有使用 Comparator 子实现类中的 compare() 方法?下面再看看 TimSort.sort() 方法,源码如下:

class TimSort{  staticvoid sort(T[] a, int lo, int hi, Comparator c,  T[] work, int workBase, int workLen) {  assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;   int nRemaining = hi - lo;  if (nRemaining < 2)  return;   if (nRemaining < MIN_MERGE) {  int initRunLen = countRunAndMakeAscending(a, lo, hi, c);  binarySort(a, lo, hi, lo + initRunLen, c);  return;  }  ...  }   private staticint countRunAndMakeAscending(T[] a, int lo, int hi,Comparator c) {  assert lo < hi; int runHi = lo + 1;  if (runHi == hi)  return 1;   if (c.compare(a[runHi++], a[lo]) < 0) {  while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)  runHi++;  reverseRange(a, lo, runHi);  } else {  while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)  runHi++;  }  return runHi - lo;  } }

   


上面的代码最后会执行到 countRunAndMakeAscending() 方法中,在执行判断语句时调用了 compare() 方法。 那么如果只用了 compare() 方法,在调用 Arrays.sort() 方法时只要传具体 compare() 重写方法的类对象。



带你读《2022技术人的百宝黑皮书》——浅析设计模式2 —— 策略模式(4)

https://developer.leiyu.cn/article/1262317?groupCode=taobaotech


/template/Home/leiyu/PC/Static