策略模式
策略模式的定义
策略模式(Strategy Pattern) 是一种比较简单的模式,也叫做政策模式(Policy Pattern)其定义如下:
Define a family of algorithms,encapsulate each one,and make them interchangeable.(定义一组 算法,将每个算法都封装起来,并且使它们之间可以互换。)ps:摘取《设计模式之禅》
这个定义非常明确,清晰的。“定义一组算法”。简单来说就是一个方法可以有多种方式来实现他,定义多种策略。
代码实现
举个例子:
import java.io.*;
class StrategyTest
{
//定义排序算法
public static void compareTo(int[] arr){
//对传进来的数组进行遍历
for(int i=0;i<arr.length-1;i++){
// 创建一个比较大小的值
int minPos=i;
//在第一个循环的基础上取出index后面的值来与之比较
for(int j=i+1;j<arr.length;j++){
//将最大的值的index下标取出来
minPos=arr[j]<arr[minPos]?j:minPos;
}
//进行交换
swapto(i,minPos,arr);
}
}
public static void swapto(int i,int j,int[] arr){
int cont=arr[i];
arr[i]=arr[j];
arr[j]=cont;
}
public static void main (String[] args) throws java.lang.Exception
{
int[] arr=new int[]{5,9,1,2};
StrategyTest.compareTo(arr);
for(int i:arr){
System.out.println(i);
}
}
}
上面是一个简单的排序算法,但是现在它的可扩展性不强,只有一个int类型的比较,假如我想要其他的类型的排序的话怎么办呢?
可以自定义一个接口来定义算法
import java.io.*;
class StrategyTest implements Comparator<StrategyTest>
{
//创建一个构造方法
public StrategyTest(int width){
this.width=width;
}
//定义一个比较的变量,这里写的不是很严谨,没有定义为私有变量,没有生成get/set方法,因为这台电脑没有idea,是在在线编辑器敲的,所有代码看起来比较乱
int width;
//这是实现接口的具体方法,由这个方法来定义算法的实现方式
public int comparableTo(StrategyTest o2){
//将两个类的width属性进行比较
if(this.width<o2.width)return 1;
else if (this.width>o2.width) return -1;
else return 0;
}
//这个是排序算法
public static void compareTo(StrategyTest[] arr){
for(int i=0;i<arr.length-1;i++){
int minPos=i;
for(int j=i+1;j<arr.length;j++){
//将width属性的最大值比较出来
minPos=(arr[j].compare(arr[minPos])==-1)?j:minPos;
}
//调用交换方法
swapto(i,minPos,arr);
}
}
public static void swapto(int i,int j,StrategyTest[] arr){
StrategyTest cont=arr[i];
arr[i]=arr[j];
arr[j]=cont;
}
//最好在生成一个toString方法!!!
public static void main (String[] args) throws java.lang.Exception
{
StrategyTest[] arr=new StrategyTest[]{new StrategyTest(5),new StrategyTest(9),new StrategyTest(1)};
StrategyTest.compareTo(arr);
for(StrategyTest i:arr){
System.out.println(i.width);
}
}
}
//定义一个接口,接口中有一个泛型方法,可由这个方法来自定义你所需要的排序算法
interface Comparable<T>{
int comparableTo(T o2);
}
以上是我自己定义了一个Comparator接口,java内部jdk中也有这样的一个方法,在java.util包中。java内部封装好了的。
虽然这个方法可以满足对象的封装比较算法,但是还是存在缺点,比如我现在还要一个比较高的对象算法,改怎么扩展呢?重新在写一个类?显然不太现实。
终于进入今天的主题了 《策略模式》
策略模式使用的就是面向对象的继承和多态机制,非常容易理解和掌握。我们再来看策略模式的三个角色。
1.Context角色:起承上启下封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。
2.Strategy抽象策略角色:策略、算法家族的抽象,通常为接口,定义每个策略或算法必须具有的方法和属性。
3.ConcreteStrategy具体策略角色:实现抽象策略中的操作,该类含有具体的算法。
问题:现在我既先要用排序算法又想用冒泡算法。那么我应该怎么在策略模式中体现呢?
话不多说!上代码
package com.fh.util.strategy;
/**
* 排序策略接口
* @author Xuzs
*/
public interface SortStrategy {
/**
* 定义一个排序接口
*/
public void sortStrategy(int[] arr);
}
package com.fh.util.strategy;
/**
* 选择排序算法
* @author Xuzs
*/
public class SelectSortStrategy implements SortStrategy{
@Override
public void sortStrategy(int[] arr) {
for (int i=0;i<arr.length;i++){
int temp=i;
for (int j=0;j<arr.length-1;j++){
temp=arr[temp]<arr[j]?temp:j;
stwp(i,temp,arr);
}
}
}
public void stwp(int i,int j,int[] arr){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
package com.fh.util.strategy;
/**
* 冒泡排序算法策略
* @author Xuzs
*/
public class BubblingSortStrategy implements SortStrategy{
/**
* 实现具体的排序算法
* @param arr
*/
@Override
public void sortStrategy(int[] arr) {
for (int j=0;j<arr.length;j++){
for(int i=0;i<arr.length-1-j;i++){
if(arr[i]<arr[i+1]){
int temp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
}
}
}
}
}
package com.fh.util.strategy;
import freemarker.template.utility.Execute;
/**
* 策略执行者
* @author Xuzs
*/
public class ExecuteStrategy {
private SortStrategy sortStrategy;
public ExecuteStrategy(SortStrategy sortStrategy){
this.sortStrategy=sortStrategy;
}
public void execute(int[] arr){
this.sortStrategy.sortStrategy (arr);
}
}
package com.fh.util.strategy;
public class Test1 {
public static void main(String[] args) {
int[] arr=new int[]{5,8,1,3};
ExecuteStrategy executeStrategy=new ExecuteStrategy (new BubblingSortStrategy ());
executeStrategy.execute (arr);
for (int i:arr){
System.out.println (i);
}
}
}
策略模式的应用
1.策略模式的优点
算法可以自由切换。
避免使用多重条件判断。
扩展性良好
2.策略模式的缺点
策略类数量增多,每一个策略对应一个类,复用的可能性比较小,类数量增多。后期维护造成一定难度
所有的策略类都需要对外暴露。上层模块必须知道有哪些策略,然后才能决定用那一种策略。这与迪米特法则是相违背的,我只是想使用一个策略,我凭什么就要了解这个策略呢?那要你的封装类还有什么意义?这是原装策略模式的一个缺点,幸运的是,我们可以使用其他模式来修正这个缺陷,如果工厂方法模式、代理模式或享元模式。
3. 策略模式的应用场景
多个类只有在算法或行为上稍有不同的场景。
算法需要自由切换的场景。
需要屏蔽算法规则的场景。
4.策略模式需要注意的事项
如果系统中的一个策略家族的具体策略数量超过4个,则需要考虑使用混合模式,解决策略类膨胀和对外暴露的问题,否则日后的系统维护就会变成一个烫手山芋。