一、概述
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。 那么我们就由实际需求出发,一步一步深入剖析设计原理。
二、解析
1. int数组排序
我们假设一种业务场景,要对一个int数组进行排序,测试类代码如下:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] a = {9,2,3,5,7,1,4};
Sorter sorter = new Sorter();
sorter.sort(a);
System.out.println(Arrays.toString(a));
}
}
其中的排序类Sorter源码如下:
public class Sorter {
public static void sort(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);
}
}
static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
测试结果如下图:
如上图所示,完美实现了排序,这是我们所预期的结果。那么在此基础上,如果我们不仅想对int类型的数组进行排序,还想对double,String甚至是自定义的类Cat等数组进行排序,那么我们就需要修改Sorter类的sort()方法的具体实现。
2. 自定义Cat类数组排序
以Cat类为研究对象,那么我们怎么知道哪只猫大哪只猫小呢?这就需要我们自己定义好比较的规则,Cat类源码如下:
public class Cat {
int weight, height;
public Cat(int weight, int heigh) {
this.height = heigh;
this.weight = weight;
}
//自定义的比较规则
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 + "]";
}
}
我们要对Cat数组进行排序,那么就需要修改Sorter类的sort()方法,修改后的源码如下:
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 sorter = new Sorter();
sorter.sort(a);
System.out.println(Arrays.toString(a));
}
}
输出结果如下:
3. 对任何类数组进行排序-泛型
如果想对其他自定义类进行排序,总不能每次都修改Sorter类的sort()方法,那么我们可以定义一个MyComparable接口,MyComparable接口中有一个比较方法compareTo(),每个类实现这个MyComparable接口并且实现自己的compareTo()方法来完成自己的比较规则。
MyComparable接口源码如下:
public interface MyComparable<T> {
int compareTo(T t);
}
Cat实现MyComparable接口后的源码如下:
public class Cat implements MyComparable<Cat>{
int weight, height;
public Cat(int weight, int heigh) {
this.height = heigh;
this.weight = weight;
}
//自定义的比较规则
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 + "]";
}
}
这样只需要让Sorter类的sort()方法针对MyComparable类型的数组进行排序,这样所有实现MyComparable接口的类都可以用自己的排序规则进行排序,Sorter类源码如下:
public class Sorter {
public static void sort(MyComparable[] 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);
}
}
static void swap(MyComparable[] arr, int i, int j) {
MyComparable temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
运行测试代码结果与上面一致,如下:
到这里,我们貌似已经解决了我们针对不同的类也能调用一个sort()方法就能够排序,但是还是有问题,现在Cat类是利用weight字段来进行比较的,如果Cat类想要换一种比较策略用height呢?显然现在的代码是无法满足的,因为Cat类只有一个compareTo()方法,只能完成一种排序规则,所以这个时候就轮到我们的策略模式登场啦!
4. Comparator-灵活指定比较策略
设计模式中我们要求满足开闭原则,对修改关闭,对拓展开放。所以我们针对不同的比较策略不能去修改Cat类的compareTo()方法,处于这样的考虑,我们可以先创建一个比较器接口Comparator,里面有一个比较方法compareTo(),源码如下:
public interface MyComparator<T> {
int compareTo(T o1,T o2);
}
根据不同的比较策略创建不同的子比较器CatComparator类,源码如下:
public class CatComparator implements MyComparator<Cat>{
@Override
public int compareTo(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 {
public void sort(Cat[] arr,MyComparator<Cat> Comparator) {
for (int i = 0; i < arr.length - 1; i++) {
int minPos = i;
for (int j = i+1; j < arr.length; j++) {
minPos = Comparator.compareTo(arr[j],arr[minPos])==-1 ? j : minPos;
}
swap(arr, i, minPos);
}
}
void swap(Cat[] arr, int i, int j) {
Cat temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
测试代码如下:
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 sorter = new Sorter();
sorter.sort(a,new CatComparator());
System.out.println(Arrays.toString(a));
}
}
测试结果如下图:
由结果我们可以看出,代码是正确的完成了排序,那么我们针对其他的比较策略,还可以创建子比较器CatHeightComparator类,源码如下:
public class CatHeightComparator implements MyComparator<Cat>{
@Override
public int compareTo(Cat o1, Cat o2) {
if (o1.height > o2.height)
return -1;
else if (o1.height < o2.height)
return 1;
else
return 0;
}
}
我们只需要在调用排序方法时,传入比较器CatHeightComparator的实例,就可以完成第二种排序策略,测试代码如下:
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 sorter = new Sorter();
sorter.sort(a,new CatHeightComparator());
System.out.println(Arrays.toString(a));
}
}
测试结果符合预期,如下:
至此,我们利用策略模式完成了所有的设想!
三、总结
总的来说,策略模式就是定义一个策略框架,每次需要用特定的策略时,我们就实现具体的规则,以此来实现策略的多变切换以达到代码的健壮性。
更多精彩内容,敬请扫描下方二维码,关注我的微信公众号【Java觉浅】,获取第一时间更新哦!