一、什么是策略模式
策略模式:它定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式的变化,不会影响到使用算法的客户。
我们来看下策略模式的UML图:
二、策略模式的构成
公共策略:定义一个接口作为公共策略,所有的算法规则实现该接口;
具体策略:封装了具体的算法和行为,继承于公共策略;
封装类:进行二次封装,维护对公共策略对象的引用;
三、实例演示
业务场景:现在我们在做一个商场的优惠活动,这个活动根据节日的不同也会调整相应的活动规则,比如五一黄金周我们是所有会员商品一律8折,节日过后恢复原价不再优惠,等到了国庆商场有有了新的促销活动,满300减150,那么根据这样的业务需求我们来看看使用策略模式到底应该怎么做?
首先我们需要创建一个公共的策略类
public interface Strategy { // 算法规则 double regulation(double money);}复制代码
接下来我们分别定义三种活动规则,首先是没有优惠活动的收费方式
public class NormalStrategy implements Strategy { @Override public double regulation(double money) { System.out.println("正常收费 : " + money); return money; }}复制代码
打折
public class DiscountStrategy implements Strategy { private double moneyDiscount = 1D; public DiscountStrategy(String discount) { this.moneyDiscount = Double.parseDouble(discount); } @Override public double regulation(double money) { System.out.println("打折优惠 : " + money * moneyDiscount); return money * moneyDiscount; }}复制代码
满300返150
public class RebateStrategy implements Strategy { // 满多少 private double moneyCondition = 0.0D; // 减多少 private double moneyRebate = 0.0D; public RebateStrategy(String moneyCondition, String moneyRebate) { this.moneyCondition = Double.parseDouble(moneyCondition); this.moneyRebate = Double.parseDouble(moneyRebate); } @Override public double regulation(double money) { // 判断是否满足返利条件 if (money > moneyCondition) { System.out.println("折扣返现 : " + (money - Math.floor(money / moneyCondition) * moneyRebate)); return money - Math.floor(money / moneyCondition) * moneyRebate; } System.out.println("不够返现条件 : " + money); return money; }}复制代码
接下来,我们需要创建一个封装类也可以叫上下文的类,对我们的活动规则进行一个维护
public class Context { private Strategy strategy; public Context(String type,double money) { switch (type) { case "正常收费": Strategy normalStrategy = new NormalStrategy(); strategy = normalStrategy; strategy.regulation(money); break; case "打5折": Strategy discountStrategy = new DiscountStrategy("0.5"); strategy = discountStrategy; strategy.regulation(money); break; case "满300减150": Strategy rebateStrategy = new RebateStrategy("300", "150"); strategy = rebateStrategy; strategy.regulation(money); break; } }}复制代码
最后我们分别来测试看下结果是否正确:
public class Main { public static void main(String[] args) { new Context("打5折", 500); new Context("正常收费", 500); new Context("满300减150", 500); }}复制代码
可能有读者就存在疑问了,这跟简单工厂模式又有什么区别呢?
第一:首先在我们的封装类中其实已经使用到了简单工厂模式,我们使用简单工厂模,我们通过这种方式的封装将判断是什么优惠的过程从客户端转移到了我们的程序中,客户不需要再去关系;
第二:我们来看下我们昨天的简单工厂模式客户端事怎么调用的,再来看看我们今天使用策略模式是怎么调用的
通过上面我们可以看到,简单工厂模式需要客户端认识两个类,也就是CarFactory和Product,而简单工厂模式只需要客户端认识一个类,也就是Context,这样就降低了我们代码的耦合性。
四、策略模式的优点
策略模式之间可以自由的切换;
增加了程序的扩展性,如果想要增加新的策略,只需要实现公共的策略即可;
避免使用多重条件,当所有的算法都堆积在一个类中,那么就不可避免的要使用条件判断来选择合适的算法;
五、策略模式的缺点
如果有新的策略确实很容易进行扩展,但是当策略多了之后维护就变得比较艰难,所以一般策略的数量一般维护在3个左右;
必须把所有的策略暴露给用户,用户好知道知道使用哪种策略;