zoukankan      html  css  js  c++  java
  • 大话设计模式读书笔记(二) 策略模式

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

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

    收费父类

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


  • 相关阅读:
    memcache详解
    redis详解
    laravel5表单验证
    MySQL添加字段和修改字段
    delete和truncate区别
    IOC 和DI(转载)
    JPA和SpringData知识梳理
    spring和springmvc配置分离
    springboot 整合 mybatis
    mongodb安装及配置
  • 原文地址:https://www.cnblogs.com/xsyfl/p/6842520.html
Copyright © 2011-2022 走看看