概要:
以不同场景下的排序
需求作为例子进行展示,如何使用策略模式一步一步提升程序拓展性
注:排序方法使用冒泡排序
版本1:直接对整型数组进行排序
main方法
int[] arr = {1,5,2,3,6,4};
// 调用排序方法,最初版本
Sorter sorter = new Sorter();
sorter.sort(arr);
// 输出结果 [1, 2, 3, 4, 5, 6]
System.out.println(Arrays.toString(arr));
Sorter 类
/**
* 排序处理。支持各种对象的排序。参考 java.comparable
*/
public class Sorter {
/**
* 排序方法 1.0
* 选择排序,依次找到每次循环的最小值并固定下来
*/
void sort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i;
for (int j = i+1; j < arr.length; j++) {
minIndex = arr[minIndex] > arr[j] ? j : minIndex;
}
swap(arr, i, minIndex);
}
}
private static void swap(int[] arr, int present, int minIndex) {
int temp = arr[present];
arr[present] = arr[minIndex];
arr[minIndex] = temp;
}
}
代码分析:
- 拓展性弱,排序只能对整型数组进行排序
- 简单直接,目标明确
版本2:支持对自定义类(狗狗)数组进行排序
main方法
Dog[] dogs = {new Dog(5), new Dog(2),new Dog(7),new Dog(3),new Dog(4)};
// 使用第二版sorter
Sorter2 sorter2 = new Sorter2();
sorter2.sort(dogs);
// 输出结果 [Dog{cost=2}, Dog{cost=3}, Dog{cost=4}, Dog{cost=5}, Dog{cost=7}]
System.out.println(Arrays.toString(dogs))
Dog类
public class Dog {
/**
* 狗狗开销
*/
private int cost;
public Dog(int cost) {
this.cost = cost;
}
/**
* 对狗狗进行排序
*
* @return 排序结果 当前比dog小,返回-1;当前与dog相等,返回0;当前比dog大,则返回1
*/
public int compareTo(Dog dog) {
if (dog.cost > this.cost) {
return -1;
} else if (dog.cost == this.cost) {
return 0;
}
return 1;
}
@Override
public String toString() {
return "Dog{" +
"cost=" + cost +
'}';
}
}
Sorter2
/**
* 排序第二版。支持狗,或者某种特定实体类的排序
* 由此,我们需要:
* 1. 入参为特定实体类的数组
* 2. 实体类自行定义个排序方法
*/
public class Sorter2 {
/**
* 排序方法 2.0
* 选择排序,依次找到每次循环的最小值并固定下来
*/
void sort(Dog[] dogs) {
for (int i = 0; i < dogs.length - 1; i++) {
int minIndex = i;
for (int j = i+1; j < dogs.length; j++) {
// 使用dog的排序方法进行排序
minIndex = dogs[minIndex].compareTo(dogs[j]) < 0 ? minIndex : j;
}
swap(dogs, i, minIndex);
}
}
private static void swap(Dog[] dogs, int present, int minIndex) {
Dog temp = dogs[present];
dogs[present] = dogs[minIndex];
dogs[minIndex] = temp;
}
}
代码分析:
- 拓展性弱,排序只能对特定自定义类数组进行排序
- 代码稍微复杂,实体类实现了compareTo方法
版本3:支持多种自定义类的排序
main 方法
Dog3[] dog3 = {new Dog3(5), new Dog3(2),new Dog3(7),new Dog3(3),new Dog3(4)};
Cat3[] cat3 = {new Cat3(5), new Cat3(2),new Cat3(7),new Cat3(3),new Cat3(4)};
Sorter3 sorter3 = new Sorter3();
sorter3.sort(dog3);
sorter3.sort(cat3);
// 排序结果
//[Dog3{age=7}, Dog3{age=5}, Dog3{age=4}, Dog3{age=3}, Dog3{age=2}]
//[Cat3{age=7}, Cat3{age=5}, Cat3{age=4}, Cat3{age=3}, Cat3{age=2}]
System.out.println(Arrays.toString(dog3));
System.out.println(Arrays.toString(cat3));
Dog3 (与Cat3同)
public class Dog3 implements SortComparable<Dog3> {
private int age;
public Dog3(int age) {
this.age = age;
}
@Override
public String toString() {
return "Dog3{" +
"age=" + age +
'}';
}
@Override
public int compareTo(Dog3 o) {
if (o.age > this.age) {
return -1;
} else if (o.age == this.age) {
return 0;
}
return 1;
}
}
SortComparable 接口,指定排序行为
public interface SortComparable<T> {
/**
* 排序行为, T 为需要指定类型的泛型
*/
int compareTo(T t);
}
Sorter3
/**
* 排序第三版。同时支持狗,猫等多种实体类排序
* 由此,我们需要:
* 1. 入参为泛型实体类的数组
* 2. 需要实体类存在同一个排序行为(接口)
* 3. 实体类自行实现这个排序行为
*/
public class Sorter3 {
/**
* 排序方法 3.0
* 选择排序,依次找到每次循环的最小值并固定下来
*/
void sort(SortComparable[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i;
for (int j = i+1; j < arr.length; j++) {
minIndex = arr[j].compareTo(arr[minIndex]) == -1 ? minIndex : j;
}
swap(arr, i, minIndex);
}
}
private void swap(SortComparable[] t, int present, int minIndex) {
SortComparable temp = t[present];
t[present] = t[minIndex];
t[minIndex] = temp;
}
}
代码分析:
- 拓展性强,可以对实现了SortComparable接口的各种实体类数组进行排序
- 代码复杂,实体类实现了compareTo这一个可变的行为
- 实体类与排序行为间耦合度较高,如果需要改变比较策略,则会改动到实体类本身
版本4:支持多种自定义类排序的同时,支持自定义排序策略
main 方法
// 使用猫咪比较器,对猫咪数组进行排序。
Cat4[] cat4 = {new Cat4(5, 2), new Cat4(2, 4),new Cat4(1, 3),new Cat4(5, 5),new Cat4(2, 6)};
Sorter4<Cat4> sorter4 = new Sorter4<>();
sorter4.sort(cat4, new Cat4SortCompareTor());
// 版本4-猫咪重量排序结果 [Cat4{high=5, weight=2}, Cat4{high=1, weight=3}, Cat4{high=2, weight=4}, Cat4{high=5, weight=5}, Cat4{high=2, weight=6}]
System.out.println(Arrays.toString(cat4));
System.out.println("=======版本4-猫咪高度排序======");
// 版本4-猫咪高度排序结果 [Cat4{high=1, weight=3}, Cat4{high=2, weight=6}, Cat4{high=2, weight=4}, Cat4{high=5, weight=2}, Cat4{high=5, weight=5}]
sorter4.sort(cat4, new Cat4HighSortCompareTor());
System.out.println(Arrays.toString(cat4));
// 使用蚊子比较器,对蚊子数组进行排序。
Mosquito[] Mosquito = {new Mosquito(5, 2), new Mosquito(2, 4),new Mosquito(1, 3),new Mosquito(5, 5),new Mosquito(2, 6)};
Sorter4<Mosquito> sorter5 = new Sorter4<>();
sorter5.sort(Mosquito, new MosquitoSpeedSortCompareTor());
// 版本4蚊子速度排序: [Mosquito{speed=5, size=5}, Mosquito{speed=5, size=2}, Mosquito{speed=2, size=6}, Mosquito{speed=2, size=4}, Mosquito{speed=1, size=3}]
System.out.println(Arrays.toString(Mosquito));
cat4 (与Mosquito类似),回归了实体本质
public class Cat4 {
private int high;
private int weight;
public Cat4(int high, int weight) {
this.high = high;
this.weight = weight;
}
public int getHigh() {
return high;
}
public void setHigh(int high) {
this.high = high;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
return "Cat4{" +
"high=" + high +
", weight=" + weight +
'}';
}
}
SortCompareTor 接口,指定排序行为
public interface SortCompareTor<T> {
int compare(T t, T t1);
}
Cat4HighSortCompareTor 猫咪高度排序策略,其它排序策略实现类似
/**
* Cat4 排序策略,使用高度进行排序
*/
public class Cat4HighSortCompareTor implements SortCompareTor<Cat4> {
@Override
public int compare(Cat4 t1, Cat4 t2) {
if (t1.getHigh() < t2.getHigh()) {
return -1;
} else if (t1.getHigh() > t2.getHigh()) {
return 1;
}
return 0;
}
}
Sorter4
/**
* 排序第四版。同时支持狗,猫等多种实体类排序,并且支持自定义排序方式
* 由此,我们需要:
* 1. 入参为泛型实体类的数组
* 2. 实体类的排序方式(比较策略)。 作为策略模式核心,每个排序策略都是一个单独的类(开闭原则,就排序方式而言。策略模式隔离了变化点)
*/
public class Sorter4<T> {
/**
* 排序方法 4.0
* 选择排序,依次找到每次循环的最小值并固定下来
* @param arr 需要排序的数组
* @param compareTor 排序方式
*/
void sort(T[] arr, SortCompareTor<T> compareTor) {
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i;
for (int j = i+1; j < arr.length; j++) {
minIndex = compareTor.compare(arr[minIndex],arr[j]) == -1 ? minIndex : j;
}
swap(arr, i, minIndex);
}
}
private void swap(T[] t, int present, int minIndex) {
T temp = t[present];
t[present] = t[minIndex];
t[minIndex] = temp;
}
}
代码分析:
- 拓展性极强,在当前排序场景下已经隔离了几乎所有变化点,后续无论是排序需求还是排序对象出现变化,排序类本身都可以做到不变。
- 代码间调用复杂,但逻辑清晰。