前面我们谈了简单工厂模式,下面我们谈一下策略模式。
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
它的优点有:
1、 提供了一种替代继承的方法,而且既保持了继承的优点(代码重用)还比继承更灵活(算法独立,可以任意扩展)。
2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
缺点:
因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量
我们以商场收银来说明一下这个模式。
商场收银软件需求很简单,营业员根据客户所购买商品的单价和数量,向客户收费。
也许有些人会这么想,这个很简单,接受用户输入的的单价和数量,把他们相乘不就可以了嘛。当然,。,那当然可以。那如果商场对某些商品进行打折活动呢。也许你会说,那还不简单,让用户输入打几折不就行了嘛。计算总价时在原来的基础上乘以折扣就是客户的收费了。也许这个时候,你想到了封装,抽象,或者用我们以前的简单工厂模式来解决这个问题。代码如下:
1;我们先写一个现金收费抽象类。
public abstract class CashSuper {
public abstract double acceptCash(double money);
}
2:正常收费子类,继承现金收费抽象类:
public class CashNormal extends CashSuper {
public double acceptCash(double money){
return money;
}
}
3:打折收费子类,继承现金收费抽象类
public class CashRebate extends CashSuper {
private double moneyRebate=0.0;//折扣
@Override
public double acceptCash(double money) {
// TODO Auto-generated method stub
return money*moneyRebate;
}
public CashRebate(String moneyRebate){
this.moneyRebate=Double.parseDouble(moneyRebate);
}
}
4:返利收费子类,如果客户满300返100
public class CashReturn extends CashSuper {
private double moneyCondition=0;//返利条件
private double moneyReturn=0;//返利
public CashReturn(String moneyCondition,String moneyReturn ){
this.moneyCondition=Double.parseDouble(moneyCondition);
this.moneyReturn=Double.parseDouble(moneyReturn);
}
public double acceptCash(double money){
double result=money;
if(money>=moneyCondition)
result=money-Math.floor(money/moneyCondition)*moneyReturn;
return result;
}
}
5:现金收费工厂类:
public class CashFactory {
public static CashSuper createCashAccept(int type ){
CashSuper cs=null;
switch(type){
case 1:
//1表示正常收费
cs=new CashNormal();
break;
case 2:
//满300返100
CashReturn cr1=new CashReturn("300","100");
cs=cr1;
break;
case 3:
//打8折
CashRebate cr2=new CashRebate("0.8");
cs=cr2;
break;
}
return cs;
}
}
6:测试类主要实例化工厂类,接受单价和数量,还有折扣和返利。
我们想想这是最好的办法吗?我们前面讲过,简单工厂模式虽然也能解决这类问题,但是我们知道这个模式只是解决对象的创建问题。而商场收银软件也许有可能会经常更改打折和返利,那我们是不是都要改动工厂呢?仔细想想,它打折和返利,只是算法的更改。为什么我们不用策略模式呢?
策略模式定义了算法家族,分别封装起来 ,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
下面我们用策略模式和简单工厂的结合解决这个问题:
原来写的CashSuper,CashNormal,CashRebate,CashReturn都不用改了,我们再加一个类:
1:cashContext类,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用。
public class CashContext {
private CashSuper cs=null;
public CashContext(int type){
switch(type){
case 1:
//正常收费
CashNormal cs1=new CashNormal();
cs=cs1;
break;
case 2:
//满300返回100
CashReturn cr2=new CashReturn("300","100");
cs=cr2;
break;
case 3:
CashRebate cr3=new CashRebate("0.8");
cs=cr3;
break;
}
}
public double GetResult(double money){
return cs.acceptCash(money);
}
}
这样就可以了,其他的任务交给客户端就行了。