在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
概述
意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。
如何解决:将这些算法封装成一个一个的类,任意地替换。
关键代码:实现同一个接口。
应用实例:
1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。
2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。
3、JAVA AWT 中的 LayoutManager。
优点:
1、算法可以自由切换。
2、避免使用多重条件判断。
3、扩展性良好。
缺点:
1、策略类会增多。
2、所有策略类都需要对外暴露。
使用场景:
1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
2、一个系统需要动态地在几种算法中选择一种。
3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
代码设计
尝试
一开始我们想对int数组排序,排序的代码如下
/**
* @Author huyouting
* @Date 2021/2/20 15:33
* @Description:
*/
//主函数类
public class Main {
public static void main(String[] args) {
int[] a{9,5,1,3,7,2,5}
Sorter sorter = new Sorter();
sorter.sort(b);
System.out.println(Arrays.toString(b));
}
}
//排序类
/**
* @Author huyouting
* @Date 2021/2/20 15:35
* @Description:
*/
public class Sorter {
public static void sort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
int minPos = i;
for (int j = i + 1; j < arr.length; j++) {
minPos = arr[j] < 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;
}
}
问题
如果我想对一个double数组进行排序,是不是得写一个double类型的排序?
如果是float类型的,又得写一个float类型的排序
如何解决?
解决方法
场景,有cat,dog类,可以通过不同动物的不同属性比较,比如身高或者体重
dog实体类
/**
* @Author huyouting
* @Date 2021/2/20 16:20
* @Description:
*/
public class Dog {
int food;
public Dog(int food) {
this.food = food;
}
@Override
public String toString() {
return "Dog{" +
"food=" + food +
'}';
}
}
首先定义一个自己写的Comparator接口
/**
* @Author huyouting
* @Date 2021/2/20 17:21
* @Description:
*/
public interface Comparator<T> {
int compare(T o1, T o2);
}
修改之前的sort排序
/**
* @Author huyouting
* @Date 2021/2/20 17:22
* @Description:
*/
public class SorterP<T> {
public void sort(T[] arr,Comparator<T> comparator) {
for (int i = 0; i < arr.length; 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;
}
}
定义一个Dog的比较器
public class DogComparator implements Comparator<Dog> {
@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;
}
}
}
主函数,传入狗的数组和比较器进行排序
public static void main(String[] args) {
Dog [] b = {new Dog(1),new Dog(3),new Dog(2)};
SorterP<Dog> sorterP = new SorterP<>();
//传入狗的数组和比较器
sorterP.sort(b,new DogComparator());
System.out.println(Arrays.toString(a));
}
这时候如果对猫进行比较,定义一个猫的数组
猫的实体类
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 +
'}';
}
}
也实现一个猫的比较器,首先我们根据猫的身高进行排序,所以实现了一个根据身高排序的比较器
/**
* @Author huyouting
* @Date 2021/2/20 17:38
* @Description:
*/
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;
}
}
}
此时的main方法
传入猫的数组并根据猫的身高进行排序
public static void main(String[] args) {
Cat [] a = {new Cat(1,1),new Cat(5,5),new Cat(3,3)};
Dog [] b = {new Dog(1),new Dog(3),new Dog(2)};
SorterP<Cat> sorterP = new SorterP<>();
//传入猫的数组和身高比较器
sorterP.sort(a,new CatHeightComparator());
System.out.println(Arrays.toString(a));
}
思考,如果这时候我又想根据猫的体重进行排序,该怎么办?
解决方案就是再定义一个猫的体重比较器
/**
* @Author huyouting
* @Date 2021/2/20 17:33
* @Description:
*/
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;
}
}
}
这时候主函数换成猫的体重比较器就行了
public static void main(String[] args) {
Cat [] a = {new Cat(1,1),new Cat(5,5),new Cat(3,3)};
Dog [] b = {new Dog(1),new Dog(3),new Dog(2)};
SorterP<Cat> sorterP = new SorterP<>();
//传入猫的数组和体重比较器
sorterP.sort(a,new CatWeightComparator());
System.out.println(Arrays.toString(a));
}
这样的设计比较灵活,如果下次想对猫的年龄进行排序,只要再定义一个年龄比较器就可以了,可扩展性高
策略模式
如果想对方法进行扩展,sort方法不需要改变,只要添加新的策略就行,在这里添加新策略就是从Comparator继承,然后传入sort
策略模式封装的就是做一件事情的时候不同的执行方式