大话设计模式读书笔记(二) 策略模式

书中通过一道题目,让"小菜"设计一个商场收银软件,营业员根据客户购买商品的数量及单价,想客户收费。,并且软件可以兼容打折,返点等优惠活动的金额计算。

一开始,小菜使用之前所学的简单工厂模式来制作这个收银软件。

收费父类

1 public abstract class CashSuper {
2     /**
3      * 收费方法
4      * @param money //原价
5      * @return
6      */
7     public abstract double acceptCash(double money); 
8 }

 

普通收费子类

 1 /**
 2  * 普通计算类
 3  *
 4  */
 5 public class CashNormal extends CashSuper{
 6 
 7     @Override
 8     public double acceptCash(double money) {
 9         
10         return money;
11     }
12     
13 }

 

打折收费类

 1 //打折类
 2 public class CashRebate extends CashSuper{
 3     
 4     private double cashRebate = 1d;//折扣
 5     
 6     public CashRebate(double cashRebate) {
 7         super();
 8         this.cashRebate = cashRebate;
 9     }
10     @Override
11     public double acceptCash(double money) {
12         return money*cashRebate;
13     }
14 }

 

满减收费类

public class CashReturn extends CashSuper{
    private double moneyCondition = 0.0d;//满多少钱开始反
    private double moneyReturn = 0.0d;//反多少钱
    public CashReturn(double moneyCondition, double moneyReturn) {
        super();
        this.moneyCondition = moneyCondition;
        this.moneyReturn = moneyReturn;
    }
    @Override
    public double acceptCash(double money) {
        return money>moneyCondition?
        money-Math.floor(money/moneyCondition)*moneyReturn:money;
    }
}

 

收费工厂类

 1 //收费工厂
 2 public class CashFactory {
 3     public static CashSuper createCashSuper(String type){
 4         CashSuper cs = null;
 5         switch (type) {
 6         case "打8折":
 7             cs=new CashRebate(0.8);
 8             break;
 9         case "满300减100":
10             cs=new CashReturn(300,100);
11             break;
12         default:
13             cs=new CashNormal();
14             break;
15         }
16         return cs;
17     }
18 }

 

主方法

 1 public class Main {
 2     public static void main(String[] args) {
 3         double totalPrice = 0.0d;//总金额
 4         String type = "满300减100";
 5         CashSuper cs =CashFactory.createCashSuper(type);
 6         double price = 400d;//未打折前金额
 7         totalPrice+=cs.acceptCash(price);//打折后金额
 8         System.out.println(totalPrice);
 9     }
10 }

 


  但是这里就遇到了我们在学习简单工厂方法时想到的问题,按照大鸟的话来讲;“简单工厂模式虽然也能解决这个问题,但是简单工厂模式只是解决对象的创建问题。而且由于工厂本身包含所有的收费方式,商场可能经常性的更改打折和满减方式,每次修改和扩展收费方式都要修改工厂类,以至于代码需要重新编译部署。这真的是很糟糕的处理方式,不是最好的方法。”


于是,引出了策略模式。。。。


策略模式(Strategy):它定义了算法家族,分别封装起来,让他们之间可以互相替代,此模式让算法的变化,不用影响使用算法的客户。

策略模式结构图

通过使用策略模式,修改代码,将打折,满减等算法,都有Context来配置,于是只需要加一个Context类和改一下主方法。

 1 public class CashContext {
 2     private CashSuper cashSuper;//收费接口
 3     public CashContext(CashSuper cashSuper) {
 4         this.cashSuper = cashSuper;
 5     }
 6     
 7     public double getResult(double money){
 8         return cashSuper.acceptCash(money);
 9     }
10 }

 

主方法:

 1 public class Main {
 2     public static void main(String[] args) {
 3         double totalPrice  =0.0d;//用于小计
 4         CashContext cc=null;
 5         String type = "满300减100";
 6         switch (type) {
 7         case "满300减100":
 8             cc=new CashContext(new CashReturn(300, 100));
 9             break;
10         case "打9折":
11             cc=new CashContext(new CashRebate(0.9));
12             break;
13         default:
14             cc=new CashContext(new CashNormal());
15             break;
16         }
17         totalPrice+=cc.getResult(400);
18         System.out.println(totalPrice);
19     }
20 }

 

但是这样又需要客户端去判断到底执行什么算法。于是引出了策略模式与简单工厂模式的结合。

于是改造CashContext和主方法

 1 public class CashContext {
 2     private CashSuper cashSuper;//收费接口
 3     public CashContext(String type) {
 4         super();
 5         switch (type) {
 6         case "满300减100":
 7             cashSuper=new CashReturn(300, 100);
 8             break;
 9         case "打9折":
10             cashSuper=new CashRebate(0.9);
11             break;
12         default:
13             cashSuper=new CashNormal();
14             break;
15         }
16     }
17     public double getResult(double money){
18         return cashSuper.acceptCash(money);
19     }
20 }

 

主方法:

 1 public class Main {
 2     public static void main(String[] args) {
 3         double totalPrice  =0.0d;//用于小计
 4         CashContext cc=null;
 5         String type = "满300减100";
 6         cc = new CashContext(type);
 7         totalPrice+=cc.getResult(400);
 8         System.out.println(totalPrice);
 9     }
10 }


  对比简单工厂模式和策略模式与工厂模式的结合, 简单工厂模式需要客户端认识两个类CashSuper和CashFactory,而策略模式和工厂模式的结合,客户端只需要认识Context一个类就可以了,代码的耦合性进一步降低。

策略模式解析:

策略模式优点:

1、它可以以相同的方式来调用所有的方法,减少了各种算法类之间的耦合。例如上面例子中,无论是打折,还是满减,客户端调用的都是Context.getResult();。

 2、简化了单元测试,每个算法都有自己的类,可以通过自己的接口进行单元测试。

3、当一个算法出现问题是,对其他算法没有影响。

策略模式应用场景:

只要在分析过程中听到有不同时间应用不同的业务规则,就可以考虑应用策略模式来处理这种变化。


策略模式的重心

  策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。

 

策略模式的缺点

  (1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。

  (2)由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。


posted @ 2017-03-30 21:01  Will_Don  阅读(188)  评论(0编辑  收藏  举报