Java设计模式之行为型模式(策略模式)
策略模式(Strategy)
1、概述
①定义
《JAVA与模式》一书中是这样定义策略模式的:
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
策略模式的策略是什么意思?有朋友可能会疑惑:在Java中,“策略”和“方法”有什么区别?首先,策略与方法含义相近,都指应对问题的办法手段。策略比方法更加宏观,更加正式,策略更加强调地位作用,可以看作是一种“升级版”的方法。在Java中,方法就是形如show()这样的,它是被包含在类或接口中的,只是类的成员(成员变量、成员方法)。在Java中,策略不在是方法那么简单。策略虽然与方法相近,但一个策略并不是一个类的成员单位,而是一个类(或接口)为单位。我们暂且可以把Java中的策略看作“策略类”(Strategy class)。
②结构
首先我们来看看策略模式的结构图:
- Strategic为策略性接口,接口中定义了一个operateStrategy()方法,方法体内期望用于实现策略性接口的算法
- Strategy1、Strategy2、Strategy3为三个独立的策略类,都实现Strategic接口的operateStrategy()方法
可见,在策略模式中,每一个策略的单位是类,而不是方法。算法被封装在策略类的内部。
· 解答疑惑
为何策略模式需要先定义一个抽象的策略接口?
答案:我们知道,在存在多个处于统一平台,拥有同等地位的类这一场景中,使这些类共同实现或继承同一个接口或父类,能够有效提高代码的扩展性和可维护性、健壮性。试想,假设现在有一个Context类,Context类中需要使用某种策略,若这些策略类没有实现共同的接口或继承共同的父类,当有策略类增加的需求时,我们不但要写定义新的策略类的代码,还要在Context类中依次添加策略类,这样就违背了开闭原则;若这些策略类实现了共同的接口或继承共同的父类,当Context需要使用某种策略时,就可以通过一个方法,这个方法以接口类或者父类类型的引用来充当参数,充分利用了Java中多态的特性,且若有增多策略类的需求时,仅需写定义新的策略类的代码,而无需修改Context中的代码。
3、实例分析
利用策略模式实现四个策略类,分别为:Plus、Minus、Multiple、Divide,由这四个策略类构成几个基本的计算器。每一个策略类中封装了对应的算法。
UML图:
代码:
/**
* @author Hanlin Wang
*/
public class StrategyMode {
public static void main(String[] args) {
//选择不同的策略Strategy:加、减、乘、除。
Plus plus = new Plus();
double res = plus.calculate("1+1+2+5");
System.out.println(res);
Minus minus = new Minus();
double res2 = minus.calculate("9-6-1");
System.out.println(res2);
Multiple multiple = new Multiple();
double res3 = multiple.calculate("4*8*2");
System.out.println(res3);
Divide divide = new Divide();
double res4 = divide.calculate("64/4/2");
System.out.println(res4);
}
}
//方法模板
interface Calculator{
double calculate(String exp);
}
//实现模板
class Plus implements Calculator{
public double calculate(String exp) {
String[] seg = exp.split("\\+");
double res = 0.0;
for (int i = 0; i < seg.length; i++) {
res += Double.parseDouble(seg[i]);
}
return res;
}
}
class Minus implements Calculator{
public double calculate(String exp) {
String[] seg = exp.split("\\-");
double res = Double.parseDouble(seg[0]);
for (int i = 1; i < seg.length; i++) {
res -= Double.parseDouble(seg[i]);
}
return res;
}
}
class Multiple implements Calculator{
public double calculate(String exp) {
String[] seg = exp.split("\\*");
double res = 1.0;
for (int i = 0; i < seg.length; i++) {
res *= Double.parseDouble(seg[i]);
}
return res;
}
}
class Divide implements Calculator{
public double calculate(String exp) {
String[] seg = exp.split("\\/");
double res = Double.parseDouble(seg[0]);
for (int i = 1; i < seg.length; i++) {
res /= Double.parseDouble(seg[i]);
}
return res;
}
}