- Comparator接口(util)和Comparable接口(lang)
- 策略模式:传入一个策略对象,通过策略对象中某一方法的调用来控制主要流程的走向(主要是通过if、?:、while……之类的控制语句起作用的)
- 解决策略写死或用传参和if来判断选哪一种策略而不能扩展、更换策略的问题
- 策略模式相当于对3中的if或switch语句进行了封装
- 设计模式的核心基本是多态,只有少数几种没有用多态
- 多态是面向对象的核心
- 策略是一种动作,与继承基类而产生不同类型有区别(has-a与is-a的区别)
UML类图
Comparator接口
- 解决实现的比较方法想要灵活指定的问题(比较大小的策略可以灵活指定)
- 加一种新功能把原来代码给拆了,违背“开闭原则”(对修改关闭,对拓展开放,程序的弹性(Extensibility、Scalability)特别好)
- compare方法:前者大于、等于、小于后者分别返回1(正值)、0、-1(负值)
- 可以通过实现不同的比较器传入sort方法来实现按不同的策略及规则排序
- 其中属性的比较用小于号时,为从小到大排序;用大于号时为从大到小排序(两个对象的先后顺序要与参数顺序一致)
排序器
package com.mashibing.dp.strategy;
public class Sorter<T> {
public void sort(T[] arr, Comparator<T> comparator) {
for(int i=0; i<arr.length - 1; i++) {
int minPos = i;
for(int j=i+1; j<arr.length; j++) {
minPos = comparator.compare(arr[j],arr[minPos])==-1 ? j : minPos;
}
swap(arr, i, minPos);
}
}
//sort(int)
void swap(T[] arr, int i, int j) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
实体类
package com.mashibing.dp.strategy;
public class Cat {
int weight, height;
public Cat(int weight, int height) {
this.weight = weight;
this.height = height;
}
@Override
public String toString() {
return "Cat{" +
"weight=" + weight +
", height=" + height +
'}';
}
}
比较器接口
package com.mashibing.dp.strategy;
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
default void m() {
System.out.println("m");
}
}
高度比较器
package com.mashibing.dp.strategy;
public class CatHeightComparator implements Comparator<Cat> {
@Override
public int compare(Cat o1, Cat o2) {
if(o1.height > o2.height) return -1;
else if (o1.height < o2.height) return 1;
else return 0;
}
}
重量比较器
package com.mashibing.dp.strategy;
public class CatWeightComparator implements Comparator<Cat> {
@Override
public int compare(Cat o1, Cat o2) {
if(o1.weight < o2.weight) return -1;
else if (o1.weight > o2.weight) return 1;
else return 0;
}
}
排序应用
package com.mashibing.dp.strategy;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
Cat[] a = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};
Sorter<Cat> sorter = new Sorter<>();
sorter.sort(a, (o1, o2)->{
if(o1.weight < o2.weight) return -1;
else if (o1.weight>o2.weight) return 1;
else return 0;
});
System.out.println(Arrays.toString(a));
}
}
Comparable接口(与Comparator功能类似但不是策略模式)
- 想要用Sort中的sort进行排序就要实现Comparable接口
- sort方法的参数类型即为Comparable接口数组类型
- 不能使用Object类型的数组,因为即便传进来的参数实现了Comparable接口也要进行强制类型转换才能使用。与其等那时候抛classCastExceptiion异常,倒不如直接规定传进来的参数必须是Comparable接口类型的数组
- 实现(重写)compareTo方法,返回正值、0、负值分别代表当前对象大于、等于、小于传进来的对象
- compareTo方法的参数是Object类型,真正实现重写这个方法时要进行强制类型转换(基类用子类的对象要强制类型转换)
- 为什么compareTo中的参数不用Comparable类型呢??
- 因为即便是用Comparable类型,他仍然要进行强制类型转换,因为真正要比较的类也只是实现了这个接口(实现接口和继承父类的强制类型转换是不是一样的?);不需要强制类型转换时,可以用接口类型没问题
- 解决上述问题的正确方法是使用泛型T;Comparable,不用作类型转换了;不指定是什么类型,就默认是Object类型,最好在用泛型时指定具体类型
- 其中属性的比较用小于号时,为从小到大排序;用大于号时为从大到小排序(两个对象要让当前对象在前面)
排序器
package com.mashibing.dp.strategy;
public class Sorter {
public static void sort(Comparable[] arr) {
for(int i=0; i<arr.length - 1; i++) {
int minPos = i;
for(int j=i+1; j<arr.length; j++) {
minPos = arr[j].compareTo(arr[minPos])==-1 ? j : minPos;
}
swap(arr, i, minPos);
}
}
//sort(int)
static void swap(Comparable[] arr, int i, int j) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
实体类
package com.mashibing.dp.strategy;
public class Cat implements Comparable<Cat> {
int weight, height;
public Cat(int weight, int height) {
this.weight = weight;
this.height = height;
}
@Override
public int compareTo(Cat c) {
if(this.weight < c.weight) return -1;
else if(this.weight > c.weight) return 1;
else return 0;
}
@Override
public String toString() {
return "Cat{" +
"weight=" + weight +
", height=" + height +
'}';
}
}
Comparable接口
package com.mashibing.dp.strategy;
public interface Comparable<T> {
// 参数用Object或者Comparable需要强制类型转换,采用泛型的写法
// int compareTo(Object o);
int compareTo(T o);
}
排序应用
package com.mashibing.dp.strategy;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
Cat[] a = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};
// Dog[] a = {new Dog(3), new Dog(5), new Dog(1)};
// Sorter sorter = new Sorter();
// sorter.sort(a)
Sorter.sort(a);
System.out.println(Arrays.toString(a));
}
}
应用
- 将策略模式运用到坦克大战中去
- 坦克的fire可以用策略模式(通过按不同的键f1、f2、……控制可打出不同的子弹)
- 策略1:默认打一颗子弹
- 策略2:四个方向打出
- 策略3:核弹
- ……
- 为什么把private改成default而不用set和get方法,在之前的坦克大战中讲过
🤏随想
- 使用泛型时,假如没有具体指定是哪个类型,则默认是Object类型!!!所以最好具体指定类型来使用
- 泛型只在编译期检查,会提示错误,运行起来就没有<>了,变成一个具体类型了(这叫类型擦除)
- 泛型不能用在static方法中吗??
- 泛型与数组的搭配使用?
- lambda表达式可以在接口中只有一个方法时使用,可以不加@FunctionalInterface注解
- 1.8之前不可以在接口中定义default方法
- 函数式接口可以有多个方法,但是只允许有一个abstarct的,其他的都应该是default的
- 一般情况下,在没有必要的情况下,不会往类的属性中添加东西,加的越多越复杂。一般来讲能用传参数就用传参数,传参数要避免new,可以使用单例模式代替