策略模式
策略模式是将算法族抽象为接口,再将此接口与业务对象组合起来,实现不同策略功能的设计模式,该模式要求所有的策略具体类都实现一个顶层接口,该顶层接口包含一个抽象的策略方法
策略模式UML类图如下
实例为比较器的一个策略模式实现
假如现在我们要对整型数组进行排序,那么我们使用排序算法就可以实现,这里我们使用选择排序来实现
public static void sorter(int[] 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] < arr[minPos] ? j : minPos;
}
swap(arr, i, minPos);
}
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
int[] arr = {1,2,40,21,6,2};
Sorter.sorter(arr);
System.out.println(Arrays.toString(arr));
}
如果要对short、long、double等数据类型数据进行排序呢,只需将sort()对应参数修改为对应类型即可,那如果我们是为对象排序呢?我们得为对象定义比较方法,下面我们来看看可扩展性的实现方式
- 创建一个比较接口,包含一个抽象的比较方法
/**
* 自定义的Comparable接口
*/
public interface Comparable<T> {
int compareTo(T t);
}
- 所有需要比较的对象都必须实现这个接口,这里我们创建一个Cat对象,包含weight和height属性,这里通过weight来比较,weight越大,Cat对象排序就越靠后
public class Cat implements Comparable<Cat>{
public int weight;
public int 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 +
'}';
}
}
- 那么sort()方法应该如何修改呢
public static void sort(Cat[] 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);
}
}
public static void swap(Cat[] arr, int i, int j) {
Cat temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
Cat[] cats = {new Cat(1,1), new Cat(5,5), new Cat(2,2)};
Sorter1.sort(cats);
System.out.println(Arrays.toString(cats));
}
在这里,Cat类实现了Comparable接口,sort()修改了参数、排序方式以及swap()参数
4. 如果我们要对Dog对象进行排序呢?同理如下:
public class Dog implements Comparable<Dog> {
public int food;
public Dog(int food) {
this.food = food;
}
@Override
public int compareTo(Dog g) {
if(this.food < g.food) return -1;
else if(this.food > g.food) return 1;
else return 0;
}
@Override
public String toString() {
return "Dog{" +
"food=" + food +
'}';
}
}
public static void sort(Dog[] 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);
}
}
public static void swap(Dog[] arr, int i, int j) {
Dog temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
Dog[] dogs = {new Dog(1), new Dog(41), new Dog(7), new Dog(2)};
Sorter1.sort(dogs);
System.out.println(Arrays.toString(dogs));
}
显然,是可以将Dog对象成功排序的,但是如果现在要对Duck对象排序呢?不可能每一次都去修改Sort类中的方法吧?
是时候展开正题了,下面将讲述如何使用策略模式来实现对象排序
- 首先,我们创建一个顶层接口,包含一个排序方法
/**
* 比较器接口,实现此接口来实现指定比较方式的比较器类
* @param <T>
*/
public interface Comparator<T> {
int compare(T o1, T o2);
}
- 接下来,我们创建CatWeightComparator,实现Compatator接口,作为我们具体的排序策略类
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;
}
}
- 然后再改造一下Sorter类,泛型增加程序的可扩展性
public class Sorter<T> {
public void sort(T[] arr, Comparator<T> tComparator) {
for(int i = 0; i < arr.length-1; i++) {
int minPos = i;
for(int j = i+1; j < arr.length; j++) {
minPos = tComparator.compare(arr[j], arr[minPos]) == -1 ? j : minPos;
}
swap(arr, i, minPos);
}
}
public void swap(T[] arr, int i, int j) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
- 接着我们来看看结果
- 至此,策略模式我们就学习完了,如果我们要对Dog类排序,只需构造一个DogComparator类,再将DogComparator传入sort()方法即可
现在学会策略模式了吗?
奥里给!