策略模式 Strategy
1、什么叫策略模式
首先:策略模式属于行为模式
指的是对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。
策略模式组成:
-
抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
-
具体策略角色:包装了相关的算法和行为
-
环境角色:持有一个策略类的引用,最终给客户端调用
2、为什么要用策略模式
优点:
1、 策略模式将公共代码提取到父类,从而避免重复的代码。
2、将行为业务逻辑和算法实现逻辑剥离出来降低耦合性
3、符合开闭原则,提高扩展性
缺点
1、客户端必须知道所有的策略类,并自行决定使用哪一个策略类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
2、 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。
3、java接口介绍
3.1、Interface Comparable
//java.lang包下
int compareTo(T o)
方法介绍:
Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
将此对象与指定对象进行顺序比较。当此对象小于、等于或大于指定对象时,返回负整数、零或正整数。
3.2、Interface Comparator
//java.util
int compare(T o1,T o2)
方法介绍:
Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
比较其两个参数的顺序。当第一个参数小于、等于或大于第二个参数时,返回负整数、零或正整数。
4、示例代码
4.1、原始示例
定义一个交换算法:
/**
* 进行排序
*/
public class MySort {
//简单到选择排序
public void Sort(int[] arr){
//遍历趟数
for (int i = 0; i < arr.length; i++) {
//寻找最小的一个数
for (int j = i+1; j < arr.length; j++) {
//找到最小到一个,返回下标
int minIndex = arr[i] < arr[j] ? i : j;
// 直接将第i个替换成最小的,便于下次比较替换
swap(arr,i,minIndex);
}
}
}
//交换
public void swap(int[] arr,int i,int minIndex){
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
测试一下:
@SpringBootTest
public class MySortTest {
@Test
void Sort(){
int[] a = {3,5,2,1,9,6,8};
MySort mySort = new MySort();
mySort.Sort(a);
for (int i : a) {
System.out.print(i);
}
}
}
测试结果
测试没问题。
4.2、问题
如果想要换成float类型排序怎么解决,如果我们用其他类,比如一个用户类怎么排序。
4.3、Comparable接口实现
首先我们调整一下我们的排序类,让他可以实现多种类的排序,那么我们可以参数必须是Comparable类型的数组,这样以来不管是什么类型的排序,他一定会去实现一个方法compareTo用来定义比较规则,MySort类修改
/**
* 进行排序
*/
public class MySort {
//简单到选择排序
public void Sort(Comparable[] arr){
//遍历趟数
for (int i = 0; i < arr.length; i++) {
//寻找最小的一个数
for (int j = i+1; j < arr.length; j++) {
//找到最小到一个,返回下标
int minIndex = arr[i].compareTo(arr[j])==-1 ? i : j;
// 直接将第i个替换成最小的,便于下次比较替换
swap(arr,i,minIndex);
}
}
}
//交换
public void swap(Comparable[] arr,int i,int minIndex){
Comparable temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
比如定义一个users类给用户类排序,用户类去实现Comparable接口
public class Users implements Comparable<Users>{
private String name;
//年龄
private Integer age;
//身高
private Integer height;
public Users(String name, Integer age, Integer height) {
this.name = name;
this.age = age;
this.height = height;
}
public Users() {
}
@Override
public int compareTo(Users o) {
if (this.age < o.getAge()) return -1;
else if (this.age > o.getAge()) return 1;
else return 0;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getHeight() {
return height;
}
public void setHeight(Integer height) {
this.height = height;
}
@Override
public String toString() {
return "Users{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
'}';
}
}
测试
@SpringBootTest
public class MySortTest {
@Test
void Sort(){
// float[] a = {3,5,2,1,9,6,8};
Users[] a = {
new Users("a",1,1),
new Users("c",3,3),
new Users("e",5,5),
new Users("d",4,4),
new Users("b",2,2),
};
MySort mySort = new MySort();
mySort.Sort(a);
for (Users i : a) {
System.out.print(i);
}
}
}
结果正常排序:
这样以来我们不需要改变排序类,想要在给其他类进行排序我们就直接让其实现Comparable接口即可。
那么问题又来了,如果当前用户类还想用身高来进行排序又该怎么办呢?
这个时候我们就需要用到策略模式了
5、策略模式实现
5.1、Comparator接口
上面我们说到用户类想用年龄进行排序,还想用身高进行排序,这个时候我们就可以使用策略模式了,这里我们使用Comparator接口来实现
首先我们看一下排序类:
/**
* 进行排序
*/
public class MySort {
//简单到选择排序
public void Sort(Object[] arr, Comparator comparator){
//遍历趟数
for (int i = 0; i < arr.length; i++) {
//寻找最小的一个数
for (int j = i+1; j < arr.length; j++) {
//找到最小到一个,返回下标
int minIndex = comparator.compare(arr[i],arr[j])==-1 ? i : j;
// 直接将第i个替换成最小的,便于下次比较替换
swap(arr,i,minIndex);
}
}
}
//交换
public void swap(Object[] arr,int i,int minIndex){
Object temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
我们的排序方法要传递两个参数,一个是我们要排序的数组,一个是实现Comparator的策略方式
只要实现了Comparator接口的策略一定会存在一个compare方法来进行比较
在看一下我们的用户类
package com.summy.entity;
import lombok.Data;
import java.util.Comparator;
public class Users{
private String name;
//年龄
private Integer age;
//身高
private Integer height;
public Users(String name, Integer age, Integer height) {
this.name = name;
this.age = age;
this.height = height;
}
public Users() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getHeight() {
return height;
}
public void setHeight(Integer height) {
this.height = height;
}
@Override
public String toString() {
return "Users{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
'}';
}
}
单纯的定义我们的用户类就好了不用去实现任何的接口,降低了耦合性
然后我们要定义我们的策略类
根据用户年龄来定义策略
package com.summy.strategy;
import com.summy.entity.Users;
import java.util.Comparator;
public class UsersAgeStrategy implements Comparator<Users> {
@Override
public int compare(Users o1, Users o2) {
if (o1.getAge() < o2.getAge()) return -1;
else if (o1.getAge() > o2.getAge()) return 1;
else return 0;
}
}
根据身高来定义策略
package com.summy.strategy;
import com.summy.entity.Users;
import java.util.Comparator;
public class UsersHeightStrategy implements Comparator<Users> {
@Override
public int compare(Users o1, Users o2) {
if (o1.getHeight() < o2.getHeight()) return -1;
else if (o1.getHeight() > o2.getHeight()) return 1;
else return 0;
}
}
我们来测试一下
@SpringBootTest
public class MySortTest {
@Test
void Sort(){
// float[] a = {3,5,2,1,9,6,8};
Users[] a = {
new Users("a",1,1),
new Users("c",3,3),
new Users("e",5,5),
new Users("d",4,4),
new Users("b",2,2),
};
MySort mySort = new MySort();
mySort.Sort(a, new UsersHeightStrategy());
for (Users i : a) {
System.out.print(i);
}
}
}
其他的不变,只要将我们的策略传递进去即可,上面是根据身高排序,如果想换回年龄,我们只需要在mySort.Sort(a, new UsersHeightStrategy());
改为mySort.Sort(a, new UsersAgeStrategy());
即可。
我们在实际工作场景中,可以自定义策略类接口,定义相应策略实现就ok了