一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情。
策略模式的定义
策略模式定义了一系列的算法,并把每一个算法封装起来,并使它们可以相互替换。策略模式使得这些算法在不影响客户端的情况下发生变化。
策略模式涉及到的角色
- 环境对象(Context): 持有Strategy的引用。
- 抽象策略对象(Strategy): 定义所有支持算法的公共接口。
- 具体策略对象(ConcreteStrategy): 以Strategy接口实现具体算法。
策略模式的实现步骤
- 实现抽象策略对象,即对具体策略对象定义一个公共接口。
- 编写具体策略类,实现定义的公共接口。
- 编写环境角色,保存一个策略对象的引用。
- 客户端编写,对环境角色中保存的引用赋值,并调用方法。
具体实现
需求
实现一个排序算法,对一个整型数组array排序。
定义一个接口(抽象策略类)
public interface IStrategy {
int[] sort(int[] array);
}
实现该接口,并实现具体的算法
这里先实现冒泡排序策略和选择排序策略两种。
/**
* 冒泡排序策略
*/
public class MaoPaoStrategy implements IStrategy {
public int[] sort(int[] array) {
for(int i=0;i<array.length-1;i++){
for(int j=0;j<array.length-i-1;j++){
if(array[j]>array[j+1]){
int temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
return array;
}
}
/**
* 选择排序策略
*/
public class SelectStrategy implements IStrategy {
@Override
public int[] sort(int[] array) {
for (int i=0;i < array.length;i++){
int k=i;//记录最小元素的下标
for (int j = i+1;j<array.length;j++){
if (array[k] > array[j]) {
k = j;
}
}
int temp = array [i];
array [i] = array[k];
array [k] = temp;
}
return array;
}
}
定义环境对象,并保存策略对象的引用
public class Context {
private IStrategy iStrategy;
public Context (IStrategy iStrategy){
this.iStrategy = iStrategy;
}
public int[] sort(int[] array){
return iStrategy.sort(array);
}
}
客户端调用,向环境对象传入具体的策略对象
public class Client {
private static Context context;
public static void main(String[] args) {
System.out.println("未排序的数组:"+Arrays.toString(new int[]{75,8,4,63,80,54,6,97,70,99}));;
context = new Context(new MaoPaoStrategy());
System.out.println("冒泡排序策略:"+Arrays.toString(context.sort(new int[]{75,8,4,63,80,54,6,97,70,99})));;
context = new Context(new SelectStrategy());
System.out.println("选择排序策略:"+Arrays.toString(context.sort(new int[]{75,8,4,63,80,54,6,97,70,99})));
}
}
策略模式的缺点
- 客户端必须知道所有的策略类,并决定使用那一个策略类。
- 每一个具体的策略都对应一个新类,结果会造成很多策略类。
策略模式的优点
- 可以动态地改变同一行为的不同实现。
- 每一个策略算法都是相互独立的,地位平等,相互之间没有依赖性。
应用场景
在Android源码中,使用策略模式的场景很多,最典型的就是在属性动画的应用
插值器
在我们使用属性动画的时候,经常设置插值器,他的作用是根据时间的流逝来计算当前属性值改变的比例,我们在设置的时候如果传null就默认使用线性插值器,系统给我们预设了很多插值器,如下
//线性插值器
public class LinearInterpolator extends BaseInterpolator {}
//加速减速插值器
public class AccelerateDecelerateInterpolator extends BaseInterpolator {}
//循环插值器
public class CycleInterpolator extends BaseInterpolator {}
LinearInterpolator,AccelerateDecelerateInterpolator,CycleInterpolator这些类都是具体策略,外部可以通过设置不同的插值器从而实现不同的效果。
估值器
估值器是属性动画中另一个使用策略模式的地方,它和插值器类似,作用是根据当前属性值改变的百分比计算改变之后的属性值,抽象策略是TypeEvaluator接口
public interface TypeEvaluator<T> {
T evaluate(float fraction, T startValue, T endValue);
}
它有很多实现类,比如IntEvaluator,ArgbEvaluator,FloatEvaluator等
public class IntEvaluator implements TypeEvaluator<Integer> {}
public class ArgbEvaluator implements TypeEvaluator {}
public class FloatEvaluator implements TypeEvaluator<Number> {}