策略模式的介绍
在开发中也经常遇到这种情况,实现某一个功能往往有许多算法或者策略,我们在实际开发中选择不同的算法或策略来完成该功能。一般的情况是我们会把所有的算法或策略写入一个类中,通过if...else...或case语句来根据实际情况来选择具体算法或策略,但是这种方法会使这个类臃肿,维护难,当增加一种算法或策略时又要修改源代码,违反了面向对象的单一原则和开闭原则。如果将这些算法或者策略抽象出来,提供一个统一的接口,不同的算法或策略有不同的实现类,在实际使用时通过动态注入来实现算法或策略的替换,这种模式扩展性高,维护性好,也就是本次所说的策略模式。
策略模式的定义
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们相互可以替换。让算法独立于客户端变化。
策略模式的使用场景
(1)需要安全的封装多种同一类型的操作时
(2)出现同一抽象类有多个子类,而又需要使用if..else..或case语句来选择具体子类时
策略模式的类图
角色介绍:
- Context - 用来操作策略的上下文环境
- Stragety - 策略的抽象
- ConcreteStragetyA、B - 具体的策略实现
策略模式的简单实现
我们在写代码时经常会遇到对一个数组排序,排序的算法有很多比如插入排序,归并排序,冒泡排序等,我们在实际开发中要选择一种算法来对数组排序,一般情况下我们会这样写
public class Client {
private static final int INSERT_SORT = 0;//插入排序
private static final int MERGE_SORT = 1;//归并排序
private static final int BUBBLE_SORT = 2;//冒泡排序
public static void main(String[] args){
Client client = new Client();
int[] a = new int[]{1, 2, 3, 4, 5, 6};
client.show(a,INSERT_SORT);
}
//显示结果
private void show(int[] a, int type){
if(type == INSERT_SORT){
insetSort(a);
}else if (type == MERGE_SORT){
mergeSort(a);
}else if (type == BUBBLE_SORT){
bubbleSort(a);
}
for(int b : a){
System.out.print(b + " ");
}
}
//插入排序算法
private void insetSort(int[] a){
//TODO...
}
//归并排序算法
private void mergeSort(int[] a){
//TODO...
}
//冒泡排序算法
private void bubbleSort(int[] a){
//TODO...
}
}
这里并不是讨论算法,就没有给出算法的具体实现,上面我们使用type类型通过if...else...语句来动态决定使用哪一种排序算法,当我们增加一种算法时,就要在函数中增加一个判断,以此类推,这样会使代码变得臃肿,一改很多处都要改。下面用策略模式进行重构,首先定义一个抽象的排序接口
抽象的排序接口,即抽象策略角色
public interface Sort{
<T> void sort(T[] a);
}
具体策略实现类
public class BubbleSort implements Sort {
@Override
public <T> void sort(T[] a) {
//这里实现冒泡排序
}
}
public class InsertSort implements Sort{
@Override
public <T> void sort(T[] a) {
//这里实现插入排序
}
}
public class MergeSort implements Sort {
@Override
public <T> void sort(T[] a) {
//这里实现归并排序
}
}
客户端,用来操作策略的上下文环境,即Context角色
public class Client {
private Sort mSort;
public static void main(String[] args){
Client client = new Client();
//设置策略
Sort bubbleSort = new BubbleSort();
client.setmSort(bubbleSort);
Integer[] a = {1, 2, 3, 4, 5, 6};
client.show(a);
}
public void setmSort(Sort mSort) {
this.mSort = mSort;
}
public void show(Integer[] a){
mSort.sort(a);
for(Integer b : a){
System.out.print(b + " ");
}
}
}
通过上述实例可以清晰的看出两者的区别,前面说通过if..else语句来解决问题,而后者是通过建立抽象,将不同的算法构建成一个个具体的策略实现,通过不同的策略注入实现算法替换。
总结
策略模式主要用来分离算法,在简化逻辑结构的同时,增强了系统的可读性,稳定性,可扩展性,这对于复杂的业务逻辑显得更为直观,
通过建立抽象,注入不同实现,从而达到很好的扩展性。
优点:
(1)结构清晰,使用直观
(2)耦合相对低,扩展方便
(3)操作封装更为彻底
缺点:
随着策略的增加,子类会变得很多