一, 回顾简单工厂模式(SimpleFactory)
上一篇博文: http://blog.youkuaiyun.com/nvd11/article/details/41855937
还是用回那个计算器作例子.
用简单工厂模式实现的UML图是这样的:
客户端关键代码:
private void BtnClicked_btnDel(){
int i = Integer.parseInt(tb_i.getText());
int j = Integer.parseInt(tb_j.getText());
Operation oper = OperationFactory.getOperationObj(i,j,"-");
lblResult.setText("" + oper.getResult());
}
可见, 使用简单工厂后, 在客户端只知道算法是Operation的子类实现的, 但是不知道具体是哪个子类(OperationAdd 还是 OperationDel).
也就是将真正的业务子类对客户端隐藏了.
正专业的讲法就是把业务类封装起来.
但是, 在上面的例子中, 即使使用了简单工厂模式把业务类封装起来, 但是还是暴露了真正的算法(方法)名字 GetResult().
二,策略模式(Strategy)定义
所谓策略模式其实跟简单工厂模式在定义上有点类似, 只不过简单工厂封装的是业务类, 而策略模式封装了方法(算法),
也就讲令客户端无法知道真正的业务方法名字.
再简单点讲,
就是利用面向对象多态, 根据子类的不同而调用不同的重写方法.
对于上面计算器的例子.
我们移除OperationFactory类, 类似地, 添加1个叫做OperationContext的类, 它的作用有点类似与工厂类OperationFactory
Factory类: 工厂, 具有1个静态方法. 根据参数的不同返回不同的类的对象. 通常不实例化工厂类, 只调用其静态方法生成对象.
Context类: 具有非静态1个方法, 根据参数对象的不同调用相同(重写自同一超类)的方法. 客户端通常会实例化这个类.
上所提到的对象所属的类都是继承(或间接继承)自同1个超类.
三,具体代码
3.1 Operation 类
跟上次的例子变化不大, 加上了Set方法.
public abstract class Operation {
private int i;
private int j;
public int getI(){
return i;
}
public void setI(int i){
this.i = i;
}
public void setJ(int j){
this.j = j;
}
public int getJ(){
return j;
}
public abstract int getResult();
}
3.2 OperationAdd 类
public class OperationAdd extends Operation{
@Override
public int getResult(){
return this.getI() + this.getJ();
}
}
3.3 OperationDel 类
public class OperationDel extends Operation{
@Override
public int getResult(){
return this.getI() - this.getJ();
}
}
3.3 OperationContext 类
public class OperationContext {
private Operation oper;
public OperationContext(Operation oper){
this.oper = oper;
}
public int compute(int i, int j){
oper.setI(i);
oper.setJ(j);
return oper.getResult();
}
}
可见它可以根据oper对象的不同, 而调用不同的同名方法, 这就是多态的基本特性!
3.5 客户端代码
private void BtnClicked_btnDel(){
int i = Integer.parseInt(tb_i.getText());
int j = Integer.parseInt(tb_j.getText());
Operation oper = new OperationDel();
OperationContext context = new OperationContext(oper);
lblResult.setText("" + context.compute(i,j));
}
3.6 UML
四, 策略模式和简单工厂模式相结合
策略模式对客户端封装(隐藏)了 业务的具体方法, 也就是说上面例子中的客户端调用OperationContext类的compute方法来计算, 而不知道真正的方法是getResutl().
但是上面的客户端暴露了OperationDel类...
而简单工厂模式的好处就是可以封装具体业务类.
所以将两个模式结合就可以同时封装业务类和业务方法(算法).
简单修改下OperationContext:
package strategy.bizobj;
public class OperationContext {
private Operation oper;
public OperationContext(Operation oper){
this.oper = oper;
}
//Simple Factory
public OperationContext(String symbol){
switch(symbol){
case "+": this.oper = new OperationAdd();
case "-": this.oper = new OperationDel();
}
}
public int compute(int i, int j){
oper.setI(i);
oper.setJ(j);
return oper.getResult();
}
}
or
class OperationContext{
private Operation operation;
public OperationContext(String symbol){
this.operation = OperationFactory.getOperation(symbol);
}
public int cal(int i, int j){
return this.operation.getResult(i,j);
}
}
class OperationFactory{
public static Operation getOperation(String symbol){
switch (symbol){
case "+": return new OperationAdd();
case "-": return new OperationDel();
}
return null;
}
}
上面的Context类就是简单工厂模式和策略模式的集合了.
此时的客户端代码:
private void BtnClicked_btnDel(){
int i = Integer.parseInt(tb_i.getText());
int j = Integer.parseInt(tb_j.getText());
OperationContext context = new OperationContext("-");
lblResult.setText("" + context.compute(i,j));
}
相当简洁, 同时隐藏(封装)了业务类和业务方法.
扩展性同样很强大, 如果需要增加乘法button, 只需要增加1个乘法类, 以及修改简单工厂内的switch 代码.