1. Comparator接口(util)和Comparable接口(lang)
  2. 策略模式:传入一个策略对象,通过策略对象中某一方法的调用来控制主要流程的走向(主要是通过if、?:、while……之类的控制语句起作用的)
  3. 解决策略写死或用传参和if来判断选哪一种策略而不能扩展、更换策略的问题
  4. 策略模式相当于对3中的if或switch语句进行了封装
  5. 设计模式的核心基本是多态,只有少数几种没有用多态
  6. 多态是面向对象的核心
  7. 策略是一种动作,与继承基类而产生不同类型有区别(has-a与is-a的区别)

UML类图

Strategy策略模式 - 图1

Comparator接口

image.png

  • 解决实现的比较方法想要灵活指定的问题(比较大小的策略可以灵活指定)
  • 加一种新功能把原来代码给拆了,违背“开闭原则”(对修改关闭,对拓展开放,程序的弹性(Extensibility、Scalability)特别好)
  • compare方法:前者大于、等于、小于后者分别返回1(正值)、0、-1(负值)
  • 可以通过实现不同的比较器传入sort方法来实现按不同的策略及规则排序
  • 其中属性的比较用小于号时,为从小到大排序;用大于号时为从大到小排序(两个对象的先后顺序要与参数顺序一致)

排序器

  1. package com.mashibing.dp.strategy;
  2. public class Sorter<T> {
  3. public void sort(T[] arr, Comparator<T> comparator) {
  4. for(int i=0; i<arr.length - 1; i++) {
  5. int minPos = i;
  6. for(int j=i+1; j<arr.length; j++) {
  7. minPos = comparator.compare(arr[j],arr[minPos])==-1 ? j : minPos;
  8. }
  9. swap(arr, i, minPos);
  10. }
  11. }
  12. //sort(int)
  13. void swap(T[] arr, int i, int j) {
  14. T temp = arr[i];
  15. arr[i] = arr[j];
  16. arr[j] = temp;
  17. }
  18. }

实体类

  1. package com.mashibing.dp.strategy;
  2. public class Cat {
  3. int weight, height;
  4. public Cat(int weight, int height) {
  5. this.weight = weight;
  6. this.height = height;
  7. }
  8. @Override
  9. public String toString() {
  10. return "Cat{" +
  11. "weight=" + weight +
  12. ", height=" + height +
  13. '}';
  14. }
  15. }

比较器接口

  1. package com.mashibing.dp.strategy;
  2. @FunctionalInterface
  3. public interface Comparator<T> {
  4. int compare(T o1, T o2);
  5. default void m() {
  6. System.out.println("m");
  7. }
  8. }

高度比较器

  1. package com.mashibing.dp.strategy;
  2. public class CatHeightComparator implements Comparator<Cat> {
  3. @Override
  4. public int compare(Cat o1, Cat o2) {
  5. if(o1.height > o2.height) return -1;
  6. else if (o1.height < o2.height) return 1;
  7. else return 0;
  8. }
  9. }

重量比较器

  1. package com.mashibing.dp.strategy;
  2. public class CatWeightComparator implements Comparator<Cat> {
  3. @Override
  4. public int compare(Cat o1, Cat o2) {
  5. if(o1.weight < o2.weight) return -1;
  6. else if (o1.weight > o2.weight) return 1;
  7. else return 0;
  8. }
  9. }

排序应用

  1. package com.mashibing.dp.strategy;
  2. import java.util.Arrays;
  3. public class Main {
  4. public static void main(String[] args) {
  5. Cat[] a = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};
  6. Sorter<Cat> sorter = new Sorter<>();
  7. sorter.sort(a, (o1, o2)->{
  8. if(o1.weight < o2.weight) return -1;
  9. else if (o1.weight>o2.weight) return 1;
  10. else return 0;
  11. });
  12. System.out.println(Arrays.toString(a));
  13. }
  14. }

Comparable接口(与Comparator功能类似但不是策略模式)

  • 想要用Sort中的sort进行排序就要实现Comparable接口
  • sort方法的参数类型即为Comparable接口数组类型
  • 不能使用Object类型的数组,因为即便传进来的参数实现了Comparable接口也要进行强制类型转换才能使用。与其等那时候抛classCastExceptiion异常,倒不如直接规定传进来的参数必须是Comparable接口类型的数组
  • 实现(重写)compareTo方法,返回正值、0、负值分别代表当前对象大于、等于、小于传进来的对象
  • compareTo方法的参数是Object类型,真正实现重写这个方法时要进行强制类型转换(基类用子类的对象要强制类型转换)
  • 为什么compareTo中的参数不用Comparable类型呢??
    • 因为即便是用Comparable类型,他仍然要进行强制类型转换,因为真正要比较的类也只是实现了这个接口(实现接口和继承父类的强制类型转换是不是一样的?);不需要强制类型转换时,可以用接口类型没问题
  • 解决上述问题的正确方法是使用泛型T;Comparable,不用作类型转换了;不指定是什么类型,就默认是Object类型,最好在用泛型时指定具体类型
  • 其中属性的比较用小于号时,为从小到大排序;用大于号时为从大到小排序(两个对象要让当前对象在前面)

排序器

  1. package com.mashibing.dp.strategy;
  2. public class Sorter {
  3. public static void sort(Comparable[] arr) {
  4. for(int i=0; i<arr.length - 1; i++) {
  5. int minPos = i;
  6. for(int j=i+1; j<arr.length; j++) {
  7. minPos = arr[j].compareTo(arr[minPos])==-1 ? j : minPos;
  8. }
  9. swap(arr, i, minPos);
  10. }
  11. }
  12. //sort(int)
  13. static void swap(Comparable[] arr, int i, int j) {
  14. T temp = arr[i];
  15. arr[i] = arr[j];
  16. arr[j] = temp;
  17. }
  18. }

实体类

  1. package com.mashibing.dp.strategy;
  2. public class Cat implements Comparable<Cat> {
  3. int weight, height;
  4. public Cat(int weight, int height) {
  5. this.weight = weight;
  6. this.height = height;
  7. }
  8. @Override
  9. public int compareTo(Cat c) {
  10. if(this.weight < c.weight) return -1;
  11. else if(this.weight > c.weight) return 1;
  12. else return 0;
  13. }
  14. @Override
  15. public String toString() {
  16. return "Cat{" +
  17. "weight=" + weight +
  18. ", height=" + height +
  19. '}';
  20. }
  21. }

Comparable接口

  1. package com.mashibing.dp.strategy;
  2. public interface Comparable<T> {
  3. // 参数用Object或者Comparable需要强制类型转换,采用泛型的写法
  4. // int compareTo(Object o);
  5. int compareTo(T o);
  6. }

排序应用

  1. package com.mashibing.dp.strategy;
  2. import java.util.Arrays;
  3. public class Main {
  4. public static void main(String[] args) {
  5. Cat[] a = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};
  6. // Dog[] a = {new Dog(3), new Dog(5), new Dog(1)};
  7. // Sorter sorter = new Sorter();
  8. // sorter.sort(a)
  9. Sorter.sort(a);
  10. System.out.println(Arrays.toString(a));
  11. }
  12. }

应用

  • 将策略模式运用到坦克大战中去
  • 坦克的fire可以用策略模式(通过按不同的键f1、f2、……控制可打出不同的子弹)
    • 策略1:默认打一颗子弹
    • 策略2:四个方向打出
    • 策略3:核弹
    • ……
  • 为什么把private改成default而不用set和get方法,在之前的坦克大战中讲过

🤏随想

  1. 使用泛型时,假如没有具体指定是哪个类型,则默认是Object类型!!!所以最好具体指定类型来使用
  2. 泛型只在编译期检查,会提示错误,运行起来就没有<>了,变成一个具体类型了(这叫类型擦除
  3. 泛型不能用在static方法中吗??
  4. 泛型与数组的搭配使用?
  5. lambda表达式可以在接口中只有一个方法时使用,可以不加@FunctionalInterface注解
  6. 1.8之前不可以在接口中定义default方法
  7. 函数式接口可以有多个方法,但是只允许有一个abstarct的,其他的都应该是default的
  8. 一般情况下,在没有必要的情况下,不会往类的属性中添加东西,加的越多越复杂。一般来讲能用传参数就用传参数,传参数要避免new,可以使用单例模式代替