定义:它定义了算法家族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户。
单看定义,是不是觉得有点虚,让我们通过生活中的例子来走进策略模式。
场景:商场收银的促销,打折或者返利的一个收银系统。
private double getResult(String choose, String price, String num){ double totalPrices; switch (choose){ //不打折 case "0": totalPrices = Double.valueOf(price)*Double.valueOf(num); break; //八折 case "1": totalPrices = Double.valueOf(price)*Double.valueOf(num)*0.8; break; //七折 case "2": totalPrices = Double.valueOf(price)*Double.valueOf(num)*0.7; break; default: throw new IllegalStateException("Unexpected value: " + choose); } return totalPrices; }
这样,一个简单的商场价格系统就设计出来了。但是仔细看代码,又出现了2个问题。1.有太多的重构代码,比如Double.valueof。2.如果增加需求,满300-20功能,又要改代码。这时候是不是想起来简单工厂模式。设计一个父类,然后不同的计算方式充当他的子类。虽然简单工厂模式是能解决这个问题。但是如果增加新的需求呢,满500-50这些。这样我们又要增加一个子类,工厂类也需要相应的改动。这种写法是不是不太合适,在简单工厂模式中,工厂类是暴露给用户的,你经常改动工厂类是不合适的,所以这时候简单工厂并不合适,所以引入策略模式。
//抽象算法类 public interface Strategy { //算法方法 public abstract void AlgorithmInterface(); }
//封装了具体的算法或行为 public class ConcreteStrategyA extends Strategy{ @Override public void AlgorithmInterface() { System.out.println("算法A实现"); } }
public class ConcreteStrategyB extends Strategy{ @Override public void AlgorithmInterface() { System.out.println("算法B实现"); } }
Context,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用。
Strategy strategy; //构造函数,初始化时传入具体的策略对象 public Context(Strategy strategy){ this.strategy = strategy; } //根据具体的策略对象,调用其算法的方法 public void ContextInterface(){ strategy.AlgorithmInterface(); }
调用方法:
public static void main(String[] args) { Context context; context = new Context(new ConcreteStrategyA()); context.ContextInterface(); context = new Context(new ConcreteStrategyB()); context.ContextInterface(); }
以上就是策略模式的基本逻辑。现在我们就来写写商场系统的策略模式。
public abstract class CashSuper { public abstract double acceptCash(double money); }
//正常收费 public class CashNormal extends CashSuper { @Override public double acceptCash(double money) { return money; } }
//打折类 public class CashRebate extends CashSuper { private double moneyRebate = 1d; public CashRebate(String moneyRebate){ this.moneyRebate =Double.valueOf(moneyRebate) ; } @Override public double acceptCash(double money) { return money*moneyRebate; } }
//满减类 public class CashReturn extends CashSuper { private double moneyCondition = 0.0d; private double moneyReturn = 0.0d; public CashReturn(String moneyCondition , String moneyReturn){ this.moneyCondition =Double.valueOf(moneyCondition) ; this.moneyReturn = Double.valueOf(moneyReturn); } @Override public double acceptCash(double money) { double result = money; if (money>= moneyCondition){ return money-Math.floor(money/moneyCondition)*moneyReturn; } return result; } }
管理
public class CashContext { private CashSuper cs; public CashContext(CashSuper csper){ this.cs = csper; } public double getResult(double money){ return cs.acceptCash(money); } }
private double getResult1(String choose, String price, String num){ CashContext cashContext; switch (choose){ //不打折 case "正常收费": cashContext = new CashContext(new CashNormal()); break; case "满300-30": cashContext = new CashContext(new CashReturn("300","30"));; break; case "满八折": cashContext = new CashContext(new CashRebate("0.8"));; break; default: throw new IllegalStateException("Unexpected value: " + choose); } double totalPrices = 0d; totalPrices = cashContext.getResult(Double.valueOf(price)*Double.valueOf(num)); return totalPrices; }
但是这种写法你不觉得怪怪的嘛,类的生成还是通过客户端去选择,这和我们的简单工厂模式很类似。所以我们就需要将策略模式和简单工厂模式结合。
public class CashContext { private CashSuper cs; public CashContext(String type){ switch (type){ //不打折 case "正常收费": cs = new CashNormal(); break; case "满300-30": cs = new CashReturn("300","30"); break; case "满八折": cs = new CashRebate("0.8");; break; default: throw new IllegalStateException("Unexpected value: " + type); } } public double getResult(double money){ return cs.acceptCash(money); }
private double getResult1(String choose, String price, String num){ CashContext cashContext; cashContext = new CashContext("满300-30");//选择方式 double totalPrices = 0d; totalPrices = cashContext.getResult(Double.valueOf(price)*Double.valueOf(num)); return totalPrices; }
你看,这种写法是不是比之前好多了。相比于工厂模式,客户端需要认识CashSupe和CashFactory,而现在客户端只需要认识CashContext,大大的降低了耦合度。
总结一下,什么叫做策略模式:
1.策略模式是一种定义一系列算法的方法,这些算法完成的都是相同的工作(都是打折、满减、正常)这些,只不过实现不一样,但是可以用相同的方式调用所有的方法,减少了算法之间的耦合。