策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。
实现某一个功能有多条途径,每一条途径对应一种类似又抽象算法,此时我们可以使用一种设计模式来实现灵活地选择解决途径,也能够方便地增加新的解决途径。
例如我们对一个int类型数组进行排序:
public class Main {
public static void main(String[] args) {
int[] a = {9, 6, 7, 5, 3, 12, 56, 120};
Sorter sorter = new Sorter();
sorter.sort(a);
System.out.println(Arrays.toString(a));
}
}
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);
}
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
运行结果如下:
[3, 5, 6, 7, 9, 12, 56, 120]
以上一个Sorter类定义了sort方法,形式参数是int类型的数组,可以实现排序,那么问题来了,我们现在需要对一个double类型,float类型排序呢,该如何做?是不是得再写个sort方法,形参定义为double和float类型呢?
下面举例,我们现在需要对Cat,dog,Car等排序,且每种类的排序方式都是不同的:
1.首先定义一个抽象比较接口类:
/**
* @Author: chuxia0811
* @Date: 2022/6/28 23:21
* @Description :比较器接口
*/
public interface Comparator<T> {
int compare(T o1, T o2);
}
2.定义一个dog类
/**
* @Author: chuxia0811
* @Date: 2022/6/28 23:12
* @Description :
*/
public class Dog {
int food;
public Dog(int food) {
this.food = food;
}
@Override
public String toString() {
return "Dog{" +
"food=" + food +
'}';
}
}
3.编写dog类的比较规则类:
/**
* @Author: chuxia0811
* @Date: 2022/6/28 23:24
* @Description :
*/
public class DogComparator implements Comparator<Dog> {
/**
* Dog类比较器
* @param o1
* @param o2
* @return
*/
@Override
public int compare(Dog o1, Dog o2) {
if (o1.food < o2.food) return -1;
else if (o1.food > o2.food) return 1;
else return 0;
}
}
4.定义sort类:里面传比较数据的数组和比较器
/**
* @Author: chuxia0811
* @Date: 2022/6/28 22:49
* @Description :对数组进行排序算法
*/
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);
}
}
void swap(T[] arr, int i, int j) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
5.运行比较:
/**
* @Author: chuxia0811
* @Date: 2022/6/28 22:49
* @Description :
*/
public class Main {
public static void main(String[] args) {
// int[] a = {9, 6, 7, 5, 3, 12, 56, 120};
Dog[] a = {new Dog(3), new Dog(1), new Dog(5)};
Sorter<Dog> sorter = new Sorter<>();
sorter.sort(a, new DogComparator());
System.out.println(Arrays.toString(a));
}
}
运行结果如下:
[Dog{food=1}, Dog{food=3}, Dog{food=5}]
再比如,我们要对Cat对象进行排序,并有两种比较方式:
/**
* @Author: chuxia0811
* @Date: 2022/6/28 22:49
* @Description :
*/
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 +
'}';
}
}
定义两种Cat类的比较器:
/**
* @Author: chuxia0811
* @Date: 2022/6/28 23:33
* @Description :Cat类比较器2,根据高度比较
*/
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;
}
}
/**
* @Author: chuxia0811
* @Date: 2022/6/28 23:33
* @Description :Cat类比较器1,根据重量比较
*/
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;
}
}
根据不同的比较器排序:
/**
* @Author: chuxia0811
* @Date: 2022/6/28 22:49
* @Description :
*/
public class Main {
public static void main(String[] args) {
// int[] a = {9, 6, 7, 5, 3, 12, 56, 120};
Cat[] a = {new Cat(3,3), new Cat(1,1), new Cat(5,5)};
Sorter<Cat> sorter = new Sorter<>();
sorter.sort(a, new CatHeightComparator());
System.out.println(Arrays.toString(a));
}
}
/**
* @Author: chuxia0811
* @Date: 2022/6/28 22:49
* @Description :
*/
public class Main {
public static void main(String[] args) {
// int[] a = {9, 6, 7, 5, 3, 12, 56, 120};
Cat[] a = {new Cat(3,3), new Cat(1,1), new Cat(5,5)};
Sorter<Cat> sorter = new Sorter<>();
sorter.sort(a, new CatWeightComparator());
System.out.println(Arrays.toString(a));
}
}
由上面可见,我们只需要比较时传不同的比较器规则类进去即可按我们的比较器定义的相应的规则进行比较了。
策略模式的优点:
1、定义一系列算法
2、避免多重条件语句
3、更好的扩展性
策略模式的缺点:
1、客户必须了解每一种策略的不同
2、增加了对象数目
3、只适合扁平的算法结构
1、出现有许多相关的类,仅仅是行为有差别的情况下,可以使用策略模式来使用多个行为中的一个来配置一个类的方法,实现算法动态切换。
2、实现同一个算法,有很多不同实现的情况下,可以使用策略模式来把这些“不同的实现”实现成为一个算法的类层次。
3、需要封装算法中,有与算法相关数据的情况下,可以使用策略模式来避免暴露这些跟算法相关的数据结构。
4、出现抽象一个定义了很多行为的类,并且是通过多个if-else语句来选择这些行为的情况下,可以使用策略模式来代替这些条件语句。