【设计模式】策略模式

系列文章目录



在这里插入图片描述

商场收银软件


现在我们要求做一个商场收银软件,,营业员根据客户所购买的单价和数量,向客户收费。我们可以用两个文本框来输入单价和数量,一个确定按钮来算出每种商品的费用,根据这个我们可以设计出第一代版本代码。

 public static void main(String[] args) {
        double price = 0; //商品单价
        int num = 0;  // 当前商品合计费用
        double totalPrice = 0; //当前所有商品费用
        double total = 0d;
        Scanner sc =new Scanner(System.in);
        do{
            System.out.println("请输入商品销售模式 1.原价 2.八折 3.七折");
            int discount = sc.nextInt();
            System.out.println("请输入商品单价 :");
            price = sc.nextDouble();
            System.out.println("请输入商品数量");
            num = sc.nextInt();
            if(price > 0&& num > 0){
                totalPrice = price * num;
                total += totalPrice;
            }
            System.out.println();
            System.out.println("单价" + price + "元,数量" + num + " 个,合计" + totalPrice+ " 元");
            System.out.println("总计 "+ total + "元");
        }
        while(price>0&& num>0);
    }

针对以上代码,如果此时需求改成对所有的商品搞八折,那么我们需要重新修改代码,然后再给商场所有的机器重新安装程序,如果有特殊情况,需要打五折,又需要修改,我们可以尝试用下拉框来解决这个问题。

增加打折

 public static void main(String[] args) {
        double price = 0; //商品单价
        int discount = 0;
        int num = 0;  // 当前商品合计费用
        double totalPrice = 0; //当前所有商品费用
        double total = 0d;
        Scanner sc =new Scanner(System.in);
        do{
            System.out.println("请输入商品销售模式 1.原价 2.八折 3.七折");
            discount = sc.nextInt();
            System.out.println("请输入商品单价 :");
            price = sc.nextDouble();
            System.out.println("请输入商品数量");
            num = sc.nextInt();
            switch(discount){
                case 1:
                    totalPrice = price * num; //正常收费
                    break;
                case 2:
                    totalPrice = price * num * 0.8; //打八折
                    break;
                case 3:
                    totalPrice = price * num * 0.7; // 打七折
                    break;
            }
            total += totalPrice;
            System.out.println();
            System.out.println("单价" + price + "元,数量" + num + " 个,合计" + totalPrice+ " 元");
            System.out.println("总计 "+ total + "元");
        }
        while(price>0&& num>0);
    }

经过这么修改之后,确实代码的灵活性更好了,但是重复代码依旧很多,可以考虑重构来调整,不过这不是最重要的,如果此时我们需求满三百返一百的促销算法,我们要怎么做呢?如果我们依旧通过上面的方法通过多加switch分支来达到目的,就需要使用函数,但是我们发现,所有的设计都并不是面向对象编程! 上篇文章中,我们为大家介绍了简单工厂模式,那么这里我们可不可以使用简单工厂模式来设计呢?

简单工厂实现

   public abstract class CashSuper{
       public abstract double acceptCash(double price, int num);
   }  
   //正常收费
   public class CashNormal extends CashSuper{
       @Override
       public double acceptCash(double price, int num) {
           return num * price;
       }
   }
    //打折收费
    public class CashRebate extends CashSuper{
        private double moneyRebate = 1d;
        //初始化时必须输入折扣率
       public CashRebate(double moneyRebate) {
           this.moneyRebate = moneyRebate;
       }
       @Override
       public double acceptCash(double price, int num) {
           return price * num * this.moneyRebate;
       }
   }
   //返利收费
    public class CashReturn extends CashSuper{
       private double moneyCondition = 0d; // 返利条件 
       private double moneyTReturn  = 0d; //返利值
        //初始化时,输入返利条件和返利值
       public CashReturn(double moneyCondition, double moneyTReturn) {
           this.moneyCondition = moneyCondition;
           this.moneyTReturn = moneyTReturn;
       }
       @Override
       public double acceptCash(double price, int num) {
           double result  = price * num;
           if(moneyCondition > 0 && result >= moneyCondition){
               result = result - Math.floor(result / moneyCondition) * moneyTReturn;
           }
           return result;
       }
   }

//收费工厂
public class CashFactory{
      public static CashSuper createCashAccept(int cashType){
          CashSuper cs = null;
          switch (cashType) {
              case 1:
                  cs = new CashNormal();
                  break;
              case 2:
                  cs = new CashRebate(0.8d);
                  break;
              case 3:
                  cs = new CashReturn(300d,100d);
                  break;
              case 4:
                  cs = new CashRebate(0.7d);
                  break;
          }
          return cs;
      }
  }

此时我们的客户端代码为

 public static void main(String[] args) {
        CashSuper cashSuper = CashFactory.createCashAccept(discount);
        totalPrices = cashSuper.acceptCash(price,num);
        total = total + totalPrices;
    }

此时好像是无论怎么改,我们都可以进行简单的处理,那么如果现在我们需要打五折和满500送200的促销活动,我们要怎么办呢?按照上述的代码思路来看,只需要在收费对象工厂中加两个条件就好,如果此时又需要增加一个满100元返10积分的话,我们只需要增加相应的积分算法就好。
虽然简单工厂能够解决这个问题,但是这个模式只是解决对象的创建问题,而且由于本身包括所有的收费方式,商场可能会经常性的更改打折额度和返利额度,每次维护都需要改动这个工厂,以致代码重新编译部署, 这样的处理方式真挺糟糕的,这是需要引入我们的策略模式!

策略模式

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

对于实例商场收银时如何促销,打折或者返利,其实都是一些算法,用工厂来生成算法对象,这并没有错,但算法本身就是一种策略,最重要的是哲学算法是随时都可能互相替换的,这就是变化点,而封转变化点是我们面向对象的一种很重要的思维方式,下面是代码示例:

  abstract class Strategy{
       public abstract void algorithmInterface();
   }
   class ConcreteStrategy extends Strategy{
       @Override
       public void algorithmInterface() {
           System.out.println("算法A的实现");
       }
   }
   class ConcreteStrategyB extends Strategy{

       @Override
       public void algorithmInterface() {
           System.out.println("算法b实现");
       }
   }
   class ConcreteStrategyC extends Strategy{

       @Override
       public void algorithmInterface() {
           System.out.println("算法c实现");
       }
   }
   class Context{
       Strategy strategy;
       public Context(Strategy strategy) {
           this.strategy = strategy;
       }
       public void contextInterface(){
           strategy.algorithmInterface();
       }
   }

    public void main(String[] args) {
        Context context;
        context = new Context(new ConcreteStrategy());
        context.contextInterface();
        context = new Context(new ConcreteStrategyB());
        context.contextInterface();
        context = new Context(new ConcreteStrategyC());
        context.contextInterface();
    }
}

下面我们用策略模式实现上文中的商场系统

public class CashContext{
     private CashSuper cs;
     public CashContext(CashSuper cashSuper) {
         this.cs = cashSuper;
     }
     public double getResult(double price,int num){
         return this.cs.acceptCash(price,num);
     }
 }
    //客户端主要代码
    public static void main(String[] args) {
        CashContext cc = null;
        switch(discount){
            case 1:
                cc = new CashContext(new CashNormal());
                break;
            case 2:
                cc = new CashContext(new CashRebate(0.7));
                break;
            case 3:
                cc = new CashContext(new CashReturn(300d,100d));
                break;
                
        }
        totalPrice = cc.getResult(price,num);
        total += totalPrice;
    }

下面我们将策略简单工厂模式结合

 public class CashContext{
    private CashSuper cs;
    public CashContext(int cashType){
        switch(cashType){
            case 1:
                this.cs = new CashNormal();
                break;
            case 2:
                this.cs = new CashRebate(0.8);
                break;
            case 3:
                this.cs = new CashReturn(200d,50d);
                break;
        }
    }
     public double getResult(double price,int num){
        return this.cs.acceptCash(price,num);
     }
 }
    //客户端
    public static void main(String[] args) {
        CashContext cc = new CashContext(discount);
        totalPrices = cc.getResult(price,num);
        total += totalPrices;
    }

这里我们观察简单工厂模式和策略模式与简单工厂模式结合两种情况在客户端代码:

//简单工厂模式用法
CashSuper csuper = CashFactory.createCashAccept(discount);
totalPrices = csuper.acceptCash(price,num);

//策略模式和简单工厂模式结合的用法
CashContext cs = new CashContext(int discount);
totalPrices = cs.getResult(price,num);

我们发现,简单工厂模式,我们需要让客户端认识两个类,分别是CashSuper和CashFactory,而策略模式和简单工厂模式相结合的用法,客户端就只需要认识一个类CashContext就可以了,耦合更加降低。

策略模式解析

策略模式是一种定义一系列算法的方法,从概念上来看,这些算法完成的都是相同的工作,只是实现不同,他可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
策略模式的具体优点呢?

1.策略模式的Strategy类层次为Context定义了一系列的可供重用的算法和行为,继承有助于析取出这些算法中的公共功能,对于打折、返利或者其他的算法,其实都是对实际商品收费的一种计算方式,通过继承可以得到它们的公共功能----GetResult,这使得算法间有了抽象的父类CashSuper。
2.策略模式简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。

总结

以上就是本文全部内容,本文主要以商场收费系统这一小程序,引入策略模式,最后改进为简单工厂设计模式+策略模式代码。感谢各位能够看到最后,如有问题,欢迎各位大佬在评论区指正,希望大家可以有所收获!创作不易,希望大家多多支持!

最后,大家再见!祝好!我们下期见!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值