前言
排序算法有很多种,冒泡排序,选择排序,快速排序等。在实际使用排序算法时只会动态地使用其中一种,针对这种情况设计排序算法类,一种常规方法就是将多种排序算法写在一个类中,每个方法对应一个排序算法;当然也可以将多个排序算法写在一个方法中,然后通过 if-else
或者 switch
语句来选择具体的排序算法。想想它存在什么问题?
- 代码臃肿,不易维护
- 如果要增加一种新的排序算法,需要修改封装排序算法的类源代码,这明显违反了 OCP 原则和单一职责原则。
要解决这个问题,就需要用到策略模式。
定义
策略模式定义了一系列的算法,把每一个算法封装起来, 并且使它们可相互替换。策略模式模式使得算法可独立于使用它的客户而独立变化。
使用场景
- 针对同一类型问题的多种处理方式,它们区别仅仅在具体行为上,策略模式可以动态地让一个对象在多个行为中选择一个。
- 一个系统需要动态地在几种算法中选择一种.
- 如果一个对象有很多的行为,而需要通过
if-else
或者switch-case
来选择具体的行为时。
策略模式的 UML 类图
- Context:用来操作策略的上下文环境;
- Strategy:策略的抽象;
- ConcreteStrategyA、ConcreteStrategyB:具体的策略实现。
策略模式实现
针对文章开头中排序算法类通过策略模式实现
第一步:定义策略接口
public interface Sort {
void sort(int[] arr);
}
第二步:具体策略实现
冒泡排序算法
public class BubbleSort implements Sort {
@Override
public void sort(int[] arr) {
System.out.println("BubbleSort");
}
}
选择排序算法
public class SelectionSort implements Sort {
@Override
public void sort(int[] arr) {
System.out.println("SelectionSort");
}
}
快速排序算法
public class QuickSort implements Sort {
@Override
public void sort(int[] arr) {
System.out.println("QuickSort");
}
}
第三步:对外提供统一排序算法入口Context
public class SortContext {
private Sort sortMethod;
public void setSortMethod(Sort sortMethod) {
this.sortMethod = sortMethod;
}
public void sort(int[] arr) {
sortMethod.sort(arr);
}
}
第四步:需求增加
public class InsertionSort implements Sort {
@Override
public void sort(int[] arr) {
System.out.println("InsertionSort");
}
}
客户端调用
public class SortClientDemo {
public static void main(String[] args) {
int[] arr = {2, 3, 5, 1, 4};
SortContext sortContext = new SortContext();
sortContext.setSortMethod(new QuickSort());
sortContext.sort(arr);
sortContext.setSortMethod(new InsertionSort());
sortContext.sort(arr);
}
}
输出
QuickSort
InsertionSort
可以看到每个排序算法彼此独立,容易维护,如果新增一个排序算法只需创建一个新排序算法类而不影响原有的算法类源代码,复合 OCP 原则和单一职责原则。
总结
策略模式优点:
1.算法可以自由切换。
2.避免使用多重条件判断。
3.扩展性良好。
策略模式缺点:
1.策略类过多导致代码臃肿。
2.所有策略类都需要对外暴露,且需要自行决定使用对应算法。
Android 源码中策略模式实现
在动画中使用到的 插值器(Interpolator) 就使用了该模式,这里以补间动画为例。
Animation.java
Interpolator mInterpolator;
public boolean getTransformation(long currentTime, Transformation outTransformation) {
...
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
...
}
Animation 通过 getTransformation
方法会根据时间插值器来获取动画的某一帧状态并应用到View上。Interpolator 的getInterpolation
方法就是根据时间获取对应的变化百分比信息。
插值器在动画中扮演很重要的角色,它将动画的速率计算封装到一个抽象中,也就是 Interpolator 中,该接口中只有一个 getInterpolation
方法,通过这个方法来计算动画流逝的时间百分比,以此来达到一些加速,匀速,减速等的效果。
这里插值器就用到了策略模式: Interpolator 就是策略接口;AccelerateInterpolator、LinearInterpolator 等就是具体的策略实现;Animation类就是操作策略的Context 上下文环境。
结构图如下:
看完这个图,是不是发现完全符合策略模式!
参考
- 干货,策略模式你不知道的
- <<Android 源码设计模式>>
网友评论