在Think in Java 的第九章接口中在9.3(完全解耦) 节中看到一个代码,贴出来如下:
- import java.util.*;
- class Processor {
- public String name() {
- return getClass().getSimpleName();
- }
- Object process(Object input) { return input; }
- }
- class Upcase extends Processor {
- String process(Object input) { // Covariant return
- return ((String)input).toUpperCase();
- }
- }
- class Downcase extends Processor {
- String process(Object input) {
- return ((String)input).toLowerCase();
- }
- }
- class Splitter extends Processor {
- String process(Object input) {
- // The split() argument divides a String into pieces:
- return Arrays.toString(((String)input).split(" "));
- }
- }
- public class Apply {
- public static void process(Processor p, Object s) {
- System.out.println("Using Processor " + p.name());
- System.out.println(p.process(s));
- }
- public static String s =
- "Disagreement with beliefs is by definition incorrect";
- public static void main(String[] args) {
- process(new Upcase(), s);
- process(new Downcase(), s);
- process(new Splitter(), s);
- }
- }
上文中用到的就是策略设计模式。 本人在上面的代码中也只是看到了抽象类而已,也就是说,有了Processor 抽象类,然后基类们继承它,仅此而已。好吧,由于在本书中并没有仔细讲解这个模式。
先问自己几个问题:
1、策略模式是什么? 2、有什么用? 3、什么场合用? 4、有什么坏处? 5、给个代码例子吧。
好奇心是一切智慧的来源。
OK,开始自问自答模式。
一、策略模式是什么呢?
《Java与模式》中这样写的,策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有相同接口的独立的类中,从而使得它们相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。
有了定义,那就来分析定义:
1、说的是属于对象的行为模式,也就是说这个模式最终针对的是对象的行为,是对对象的行为的高度抽象化,那么为什么要对对象的行为再高度抽象化呢?这里还不知道,来看下面的。
2、它的用意是针对一组算法,将每一个算法封装到具有相同接口的独立的类中,从而使得它们相互替换。这句话有点麻烦,它可能想说,将一个相同的一组算法封装到一个接口中。 类似于下面的代码:
3、策略模式使得算法可以在不影响客户端的情况下发生变化。 这个是最终的目的。
二、有什么用啊?也就是说有什么好处啊?
可以一句话概括:可以动态的改变对象的行为,扩展性好啊。
三、什么场合用?
1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态的让一个对象在许多行为中选择一种行为。
2、一个系统需要动态的在几种算法中选择一种。
3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
注解:注意到了吗?也就是说,如果说是都是计算,计算有加,减,乘,除四种的话,用户可以选择一种,那么实现这个就可以使用策略模式。重点在于有多种选择,而后选择性的计算,如果不这么干,就只能用多重的条件选择了。
四、有什么坏处?
五、给个代码例子吧。
步骤 1
创建一个接口。
Strategy.java
public interface Strategy {
public int doOperation(int num1, int num2);
}
步骤 2
创建实现接口的实体类。
OperationAdd.java
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
OperationSubstract.java
public class OperationSubstract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
OperationMultiply.java
public class OperationMultiply implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
步骤 3
创建 Context 类。
Context.java
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
步骤 4
使用 Context 来查看当它改变策略 Strategy 时的行为变化。
StatePatternDemo.java
public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubstract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
}
}
步骤 5
验证输出。
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
六、总结
- 在策略模式中定义了一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式。策略模式是一种对象行为型模式。
- 策略模式包含三个角色:环境类在解决某个问题时可以采用多种策略,在环境类中维护一个对抽象策略类的引用实例;抽象策略类为所支持的算法声明了抽象方法,是所有策略类的父类;具体策略类实现了在抽象策略类中定义的算法。
- 策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略类里面,作为一个抽象策略类的子类。
- 策略模式主要优点在于对“开闭原则”的完美支持,在不修改原有系统的基础上可以更换算法或者增加新的算法,它很好地管理算法族,提高了代码的复用性,是一种替换继承,避免多重条件转移语句的实现方式;其缺点在于客户端必须知道所有的策略类,并理解其区别,同时在一定程度上增加了系统中类的个数,可能会存在很多策略类。
- 策略模式适用情况包括:在一个系统里面有许多类,它们之间的区别仅在于它们的行为,使用策略模式可以动态地让一个对象在许多行为中选择一种行为;一个系统需要动态地在几种算法中选择一种;避免使用难以维护的多重条件选择语句;希望在具体策略类中封装算法和与相关的数据结构。