1.适用性
当存在以下情况时使用STRATEGY模式
a.许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。
b.需要使用一个算法的不同变体。例如,你可能会定义一些反映不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时,可以使用策略模式。
c.算法使用客户不应该知道的数据。可以使用策略模式以避免暴露复杂的、与算法相关的数据结构。
d.一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以替代这些条件语句。
2.参与者
Strategy(策略): 定义所有支持的算法的公共接口。Context使用这个接口来调用某种ConcreteStrategy定义的算法。
ConcreteStrategy(具体策略):以Strategy接口实现某种具体算法。
Context(上下文):用一个ConcreteStategy对象来配置;维护一个对Strategy对象的引用;可定义一个接口让Strategy访问它的数据。
3.优缺点
优点:
a.相关算法系列:Strategy类层次为Context定义了一系列的可供重用的算法或行为。继承有助于析取算法中的公共的功能。
b.一个替代继承的方法:可以直接生成一个Context的子类,从而给它以不同的行为。但是,这会将行为硬编码到Context中,而将算法的实现和Context的实现混合起来,使得Context难以理解、维护和扩展,而且还不能动态的改变算法。
c.消除了一些条件语句:没有使用strategy模式的代码很有可能会被设计成在一个类中,使用if判断条件执行相应的策略。
d.实现的选择:客户端可以根据要求从不同的策略中进行选择。
缺点:
a.Strategy和Context之间的通讯开销: 无论各个ConcreteStrategy实现的算法是简单还是复杂,他们都会共享Strategy定义的接口。因此很可能某些ConcreteStrategy不会都用到所有通过这个接口传递给他们的信息。简单的ConcreteStrategy可能不会使用其中的任何信息,这就意味着有时Context会创建和初始化一些永远不会用到的参数。如果存在这样的问题,那么将需要在Strategy和Context之间进行紧密的耦合。
b.增加了对象的数目
4.实例
package strategy;
/**
* Description: 策略接口类
*
* @author
* @version 1.0
* @since 2017-08-02 5:46 PM
*/
public interface Strategy {
void algorithmInterface();
}
package strategy;
/**
* Description: 具体策略A
*
* @author
* @version 1.0
* @since 2017-08-02 5:47 PM
*/
public class ConcreteStrategyA implements Strategy {
@Override
public void algorithmInterface() {
System.out.println("策略A执行");
}
}
package strategy;
/**
* Description: 具体策略B
*
* @author
* @version 1.0
* @since 2017-08-02 5:48 PM
*/
public class ConcreteStrategyB implements Strategy {
@Override
public void algorithmInterface() {
System.out.println("策略B执行");
}
}
package strategy;
/**
* Description: 具体策略C
*
* @author
* @version 1.0
* @since 2017-08-02 5:49 PM
*/
public class ConcreteStrategyC implements Strategy {
@Override
public void algorithmInterface() {
System.out.println("策略C执行");
}
}
package strategy;
/**
* Description: 上下文配置类
*
* @author yunqiangdi
* @version 1.0
* @since 2017-08-02 5:49 PM
*/
public class Context {
//持有策略接口的引用
private Strategy strategy;
/**
* 用其中某个策略初始化上下文
* @param strategy 具体的策略类
*/
public Context(Strategy strategy) {
this.strategy = strategy;
}
/**
* 进行策略的具体执行
*/
public void operator() {
strategy.algorithmInterface();
}
}
package strategy;
/**
* Description: 策略测试类
*
* @author yunqiangdi
* @version 1.0
* @since 2017-08-02 5:55 PM
*/
public class StrategyTest {
public static void main(String[] args) {
Strategy strategy = new ConcreteStrategyA();
Context ctx = new Context(strategy);
ctx.operator();
}
}
第二种表示策略的方式为使用匿名内部类表示策略(这种也可以把匿名内部类当作一个函数对象)。
package strategy.example2;
/**
* @author koou
* @version 1.0
* @since 2017-08-05 下午 13:26
*/
public interface Strategy<T> {
/**
* 策略接口
* @param t 策略执行
*/
<T> void process(T t);
}
package strategy.example2;
/**
* @author koou
* @version 1.0
* @since 2017-08-05 下午 13:27
*/
public class StrategyProcess {
/**
* @param t 策略的执行对象
* @param strategy 具体策略
*/
public static <T> void apply(T t, Strategy<T> strategy) {
strategy.process(t);
}
}
package strategy.example2;
import java.util.Arrays;
/**
* @author koou
* @version 1.0
* @since 2017-08-05 下午 13:30
*/
public class StrategyTest {
public static void main(String[] args) {
int[] iarray = {1, 2, 3, 4, 5};
//对int数组进行策略操作,修改数组第一个数字为9097
StrategyProcess.apply(iarray, new Strategy<int[]>() {
public <T> void process(T t) {
int[] temparray = (int[]) t;
if (temparray.length > 1) {
temparray[0] = 9097;
}
}
});
System.out.println(Arrays.toString(iarray));
}
}
[9097, 2, 3, 4, 5]
由匿名内部类每次执行的时候会创建一个新的实例,如果它被重复执行,考虑将函数对象存储到一个私有的静态final域中。
package strategy.example3;
import java.io.Serializable;
import java.util.Comparator;
/**
* @author koou
* @version 1.0
* @since 2017-08-05 下午 17:03
*/
public class Host {
private static class StrLenCmp implements Comparator<String>, Serializable {
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
}
//具体的策略
public static final Comparator<String> STRING_LEN_COMPARATOR = new StrLenCmp();
}
package strategy.example3;
import java.util.Arrays;
/**
* @author koou
* @version 1.0
* @since 2017-08-05 下午 17:09
*/
public class StrategyTest {
public static void main(String[] args) {
String[] strArray = {"I", "am", "sk", "I"};
Arrays.sort(strArray, Host.STRING_LEN_COMPARATOR);
System.out.println(Arrays.toString(strArray));
}
}
测试结果:[I, I, am, sk]