概述:
策略模式定义了一系列的算法,并将这些算法一个个封装起来, 并且使它们可相互替换
emmm,这是什么意思呢?单看定义确实有那么一点点晦涩难懂,不如先看下策略模式有哪些角色。
策略模式的三个角色:
1、策略角色:策略是一个接口,接口中定义了要实现的算法。
2、具体策略角色:具体策略是实现策略接口的类,并将接口中的方法实现。
3、策略上下文角色:策略上下文依赖于策略接口的类,也就是说上下文包含有策略声明的变量。
其实就是策略模式需要一个接口(这个接口就是策略角色),接口中有方法。既然我们创建了接口,那肯定是要用他的,所以需要一个类(具体策略角色)来实现这个接口。至于策略上下文角色,他就是一个依赖于策略接口的类,类中的方法通过调用策略接口来完成对应的功能。
下面通过一个例子来了解下策略模式和上面的定义。
我们假设写个接口,来实现狗的体重的大小比较。
定义接口:(策略角色)
package com.dong.patten.strategy;
/**
* @author 雪浪风尘
* @Remember Keep thinking
*/
public interface Comparator<T> {
int compare(T o1,T o2);
}
一个实现接口的类(这个类就是具体策略角色)
package com.dong.patten.strategy;
/**
* @author 雪浪风尘
* @Remember Keep thinking
*/
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;
}
}
因为是比较狗的食量,所以需要创建狗的对象。当然了这个是这个例子需要创建对象,具体的情况还要具体对待。
dog对象:
package com.dong.patten.strategy;
/**
* @author 雪浪风尘
* @Remember Keep thinking
*/
public class Dog {
int food;
public Dog(int food) {
this.food = food;
}
@Override
public String toString() {
return "Dog{" +
"food=" + food +
'}';
}
}
策略上下文角色:
package com.dong.patten.strategy;
/**
* @author 雪浪风尘
* @Remember Keep thinking
*/
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;
}
}
这里只是一个简单的排序,将传入的数组中的对象进行简单的排序。
至此,策略模式主要的部分已经完成,我们写个例子测试一下;
package com.dong.patten.strategy;
import java.util.Arrays;
/**
* @author 雪浪风尘
* @Remember Keep thinking
* 策略模式封装的是做一件事情的不同的执行方式
*/
public class Main {
public static void main(String[] args) {
Dog[] a={new Dog(3),new Dog(5),new Dog(1)};
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}]
看到这里,你是否会想:写这么多不是挺麻烦的,直接定义对象,然后比较不就可以了。
对于单个对象来说,确实是可以的,但是如果后期要维护、修改,或者新增对象呢?比如新增猫对象的比较,我们可能还需要在原有基础上,需要原来方法中的代码,这样一来,就违反了“开-闭原则”。
使用策略模式,当我们新增时,只需要添加新的具体策略角色即可,不需要对方法进行修改,既满足了“开-闭原则”,又不会因为修改代码,而造成未知的bug。
比如,这波我们新增一个猫对象的比较:
原有的策略角色、策略上下文角色都不需要修改,只需要新增一个具体策略角色即可。
package com.dong.patten.strategy;
/**
* @author 雪浪风尘
* @Remember Keep thinking
*/
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;
}
}
因为参数类型是猫这个对象,所以需要创建猫的对象:
package com.dong.patten.strategy;
/**
* @author 雪浪风尘
* @Remember Keep thinking
*/
public class Cat{
int height,weight;
public Cat(int height, int weight) {
this.height = height;
this.weight = weight;
}
@Override
public String toString() {
return "Cat{" +
"height=" + height +
", weight=" + weight +
'}';
}
}
OK,测试一下:
package com.dong.patten.strategy;
import java.util.Arrays;
/**
* @author 雪浪风尘
* @Remember Keep thinking
* 策略模式封装的是做一件事情的不同的执行方式
*/
public class Main {
public static void main(String[] args) {
Cat[] a={new Cat(3,3),new Cat(5,5),new Cat(1,1)};
// Dog[] a={new Dog(3),new Dog(5),new Dog(1)};
Sorter<Cat> sorter=new Sorter();
sorter.sort(a,new CatWeightComparator());
System.out.println(Arrays.toString(a));
}
}
运行结果:
[Cat{height=1, weight=1}, Cat{height=3, weight=3}, Cat{height=5, weight=5}]
可以看到,我们只需要新增具体策略角色即可,不需要修改什么接口啦,上下文对象啦,而且也比较省事。
代码已经提交到github上:
https://github.com/PonnyDong/pattern
后续的代码的更新也会在上面进行更新