1、策略模式(Strategy):他定义了家族算法,分别封装起来,让他们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户。
2、策略模式结构图
3、简单代码实现
3.1、Strategy类,定义所有支持的算法的公共接口
//抽象算法类
public abstract class Strategy {
//算法方法
public abstract void AlgorithmInterface();
}
3.2concreteStrategy,封装了具体的算法或行为,继承于Strategy
//具体算法A
public class ConcreStrategyA extends Strategy {
// 算法A实现方法
@Override
public void AlgorithmInterface() {
System.out.println("实现算法A");
}
}
//具体算法B
public class ConcreStrategyB extends Strategy {
//算法B实现方法
@Override
public void AlgorithmInterface() {
System.out.println("实现算法B");
}
}
//具体算法c
public class ConcreStrategyC extends Strategy {
//算法C实现方法
@Override
public void AlgorithmInterface() {
System.out.println("实现算法C");
}
3.3Context,用一个concreteStrategy来配置,维护一个Strategy对象的引用。
public class Context {
Strategy strategy = null;
//初始化时传入具体的策略对象
public Context(Strategy strategy) {
this.strategy = strategy;
}
//根据具体的策略对象,调用其算法的方法
public void ContextInterface() {
strategy.AlgorithmInterface();
}
}
3.4使用
public class DoStrategy {
/**
* 由于实例化不同的策略,所以最终在调用context.ContextInterface()
* 时,所获得的结果不同
* @param args
*/
public static void main(String[] args) {
Context context=null;
context=new Context(new ConcreStrategyA());
context.ContextInterface();
context=new Context(new ConcreStrategyB());
context.ContextInterface();
context=new Context(new ConcreStrategyC());
context.ContextInterface();
}
4、书上超市收银系统的例子,主要解决随时变化的打折策略,例如直接打折、正常收费、满减等。主要使用简单工厂模式+策略模式实现
4.1收款策略抽象类
public abstract class CashSuper {
// 现金收取超类的抽象方法,收取现金,参数为原价,返回为当前价
public abstract double acceptCash(double money);
}
4.2 收款策略子类
//普通收款
public class CashNormal extends CashSuper {
public double acceptCash(double money) {
return money;
};
}
//打折收款
public class CashRebate extends CashSuper {
private double moneyRebate=0;
//创建打折对象时必须输入折扣率
public CashRebate(double moneyRebate) {
// TODO Auto-generated constructor stub
this.moneyRebate=moneyRebate;
}
@Override
public double acceptCash(double money) {
return money*moneyRebate;
}
}
//满减返现
public class CashReturn extends CashSuper {
// 返利条件,例如满300
private double moneyCondition = 0;
// 返利值,例如返100
private double moneyReturn = 0;
public CashReturn(double moneyCondition, double moneyReturn) {
this.moneyCondition = moneyCondition;
this.moneyReturn = moneyReturn;
}
@Override
public double acceptCash(double money) {
// TODO Auto-generated method stub
double result = money;
if (money > moneyCondition) {
result = money - Math.floor(money / moneyCondition) * moneyReturn;
}
return result;
}
}
4.3 收款策略context和收款策略简单工厂结合
public class CashContext {
CashSuper cs=null;
//通过构造方法传入具体的收费策略
public CashContext(String type) {
switch(type) {
case "正常收费":
cs=new CashNormal();
break;
case "满300返100":
cs=new CashReturn(300,100);
break;
case "打8折":
cs=new CashRebate(0.8);
break;
}
}
public double getResult(double money) {
return cs.acceptCash(money);
}
}
4.4 收款客户端
public class CheckOut {
public static void main(String[] args) {
// 选择优惠算法
CashContext csuper = new CashContext("打8折");
// 输入收款金额
double result = csuper.getResult(800);
System.out.println("付款金额:"+result);
}
}
4.5、收款系统总结
1、只使用策略模式时,在客户端还是需要判断收款的类型,造成代码不够简洁。
2、只使用工厂模式时,客户需要认识CashSuper和CashFactory两个类。
3、同时使用策略模式和工厂模式,客户端只需要认识CashFactory一个类,降低了客户端的耦合度,彻底的将算法从客户端分离。
5、总结
1、策略模式是定义一系列算法的的方法,从概念上来看,所有的这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
2、策略模式的Strategy类层次为Context定义了一系列的可供重用的算法或行为。继承有助于提出出这些算法的公共功能。
3、策略模式的优点是简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
4、策略模式就是用来封装算法的,但是在实践中,我们发现可以用它来封装几乎任何类型的规则,只需要在分析过程中发现需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。
5、策略模式和工厂模式结合后仍然存在添加策略虚要修改switch代码,任何需求的变更都是需要成本的。