一、概述
策略模式(strategy),它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式算法的替换不会影响到使用算法的客户。
二、编程实现
该程序主要通过模拟商场收费打折的功能实现。
1、创建现金收费抽象类
public abstract class CashSuper {
public abstract double acceptCash(double money);
}
2、创建各种收费的具体实现
2.1 正常收费
public class CashNormal extends CashSuper {
@Override
public double acceptCash(double money) {
return money;
}
}
2.2 返利收费 满300送100
public class CashReturn extends CashSuper {
private double moneyCondition;
private double moneyReturn;
public CashReturn(double moneyCondition, double moneyReturn) {
this.moneyCondition = moneyCondition;
this.moneyReturn = moneyReturn;
}
@Override
public double acceptCash(double money) {
double result = 0d;
if(money > moneyCondition){
result = money - Math.floor(money/moneyCondition) * moneyReturn;
}
return result;
}
}
2.3 打折收费
public class CashRebate extends CashSuper {
private double rebateRate = 1d;
public CashRebate(double rebateRate) {
this.rebateRate = rebateRate;
}
@Override
public double acceptCash(double money) {
return money*rebateRate;
}
}
3、context上下文,维护一个对Strategy对象的引用
public class Context {
private CashSuper cashSuper;
public Context(CashSuper cashSuper) {
this.cashSuper = cashSuper;
}
public double getMoney(double money){
return cashSuper.acceptCash(money);
}
}
4、策略模式测试
//策略模式应用
Context context = null;
String type = "normal";
switch (type){
case "normal":
context = new Context(new CashNormal());
break;
case "return":
context = new Context(new CashReturn(300,100));
break;
case "rebate":
context = new Context(new CashRebate(0.8));
break;
}
double total = context.getMoney(2000);
System.out.println(total);
至此,策略模式的解释已经结束,可以看出以上代码的优缺点:
优点:1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性好。
缺点:1、客户端必须知道所有的策略类,并自己决定由那个策略类。 2、策略类会很多。
解决这个缺点方法:策略+简单工厂
5、策略模式+简单工厂结合
策略模式需要在客户端判断用哪个算法,那么为了解决这个问题就可以将策略模式和简单工厂结合起来。具体的方法就是 简单工厂与策略模式中的Context类结合
改进的Context代码:
public class SimpleFactoryContext {
CashSuper cashSuper = null;
public SimpleFactoryContext(String type){
switch (type){
case "normal":
cashSuper = new CashNormal();
break;
case "return":
cashSuper = new CashReturn(300,100);
break;
case "rebate":
cashSuper = new CashRebate(0.8);
break;
}
}
public double getResult(double money){
return cashSuper.acceptCash(money);
}
}
优点:解决了需要在客户端判断使用那个实现的缺点;
缺点:在cashContext中用到了swith,也就是说,如果我们需要增加一种算法,比如"满200减50",就必须更改cashContext中的switch代码。
6、策略模式+简单工厂+反射机制
策略模式需要在客户端判断用哪个算法,那么为了解决这个问题就可以将策略模式和简单工厂结合起来。具体的方法就是 简单工厂与策略模式中的Context类结合
改进的Context代码:
public class FsContext {
private static final String[] CUSH_CLASS_NAME = {
"com.zbf.strategyMode.CashNormal",
"com.zbf.strategyMode.CashRebate",
"com.zbf.strategyMode.CashReturn"
};
CashSuper cashSuper = null;
public FsContext(int type,Class[] paramsType, Object[] params){
try {
Class<?> clazz=Class.forName(CUSH_CLASS_NAME[type]);
Constructor<?> constructor=clazz.getConstructor(paramsType);
this.cashSuper=(CashSuper)constructor.newInstance(params);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public double getResult(double money){
return cashSuper.acceptCash(money);
}
}
7、测试
/**
* 策略模式与简单工厂模式的结合,使得客户端只需知道sfc类即可,而单纯的策略模式客户端需要认识context及caseSuper,
* 此方式降低了耦合度
*/
SimpleFactoryContext sfc = new SimpleFactoryContext("return");
double m = sfc.getResult(2000);
System.out.println(m);
//反射机制
Class[] paramTypes2 = {double.class};
Object[] params2 = {0.8d};
FsContext fc = new FsContext(1,paramTypes2,params2);
double mon = fc.getResult(2000);
System.out.println(mon);
注:参考文献《大话设计模式》程杰著。