大话设计模式——第二章:商场促销策略模式


前言

做一个商场收银软件,营业员根据客户所购买商品的单价和数量,向顾客收费。


一、代码1.0

1.1. 代码

public class StrategyMode {
    public static void main(String[] args) {
        double total = 0;
        //实际的price 和count可以做个界面,从框中取值
        double price = 3;
        int count = 5;
        total = price * count;
        System.out.println("商品合计总价:"+total);
    }
}

实际可以做一个界面出来,用两个文本框输入单价和数量,一个确定按钮来算出每种商品的费用,用个列表框来记录商品的清单,一个标签来记录总数,一个按钮重新开始。

2.2. 存在的问题

如果要打八折,可以使用total*0.8,但是如果不打折了,需要重新修改一遍代码,或者打五折,都需要重新去修改代码。

二、代码1.1 增加打折

2.1. 代码

public class StrategyMode {
    public static void main(String[] args) {
        double total = 0;
        //实际的price 和count可以做个界面,从框中取值
        double price = 3;
        int count = 5;
        total = getTotal("打五折",price,count);
        System.out.println("商品合计总价:"+total);
    }
    public static double getTotal(String type, double price, int count){
        double totalPrice = 0;
        switch (type){
            case "正常收费":
                totalPrice = price * count;
                break;
            case "打八折":
                totalPrice = price * count * 0.8;
                break;
            case "打五折":
                totalPrice = price * count * 0.5;
                break;
        }
        return totalPrice;
    }
}

2.2. 存在的问题

三个switch分支语句除了打折多少以外几乎没什么不同,应该考虑重构一下。

如果增加需求要满300-30,还得修改促销类型代码。

在这里可以使用简单工厂模式,先写一个父类,在继承它实现多个打折和返利的子类,利用多态来解决问题。

而且不用打五折、打八折、满300送30,满500送60都分别写一个类,可以将打折写一个类,返利写一个类。

三、代码2.0 使用简单工厂写打折类和返利类

打折基本上是一样得,只要有个初始化参数就可以了。返利需要两个参数。

面向对象编程并不是类越多越好,类得划分是为了封装,但分类得基础是抽象,具有相同属性和功能得对象得抽象集合才是类。

打八折和打五折只是形式不同,抽象分析出来,所有的打折算法都是一样的,所以打折算法是一个类。

3.1. 代码

//现金收取超类

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 = 1;
    public CashRebate(double moneyRebate){
        this.moneyRebate = moneyRebate;
    }
    @Override
    public double acceptCash(double money) {
        return money * moneyRebate;
    }
}

//返利类

public class CashReturn extends CashSuper{
    //返利条件
    private double moneyCondition = 0;
    //返利值
    private double moneyReturn = 0;
    public CashReturn (double moneyCondition,double moneyReturn){
        this.moneyCondition = moneyCondition;
        this.moneyReturn = moneyReturn;
    }
    @Override
    public double acceptCash(double money) {
        if (money > moneyCondition){
            return moneyCondition - moneyReturn;
        }else {
            return money;
        }
    }
}

//现金收费工厂类

public class CashFactory {
    public static CashSuper createCashAccept(String type){
        CashSuper cs = null;
        switch (type){
            case "正常收费":
                cs = new CashNormal();
                break;
            case "打八折":
                cs = new CashRebate(0.8);
                break;
            case "满300返100":
                cs = new CashReturn(300,100);
                break;
        }
        return cs;
    }
}

客户程序主要部分:

public class StrategyMode {
    public static void main(String[] args) {
        CashSuper cs = CashFactory.createCashAccept("打八折");
        double result = cs.acceptCash(88);
        System.out.println("最后的金额为:"+result);
    }
}

3.2. 存在的问题

如果需要打五折或者满500减60,需要在收费对象生成工厂增加两个条件。

如果需要增加另外一种促销方式,比如:满100积分10点,以后积分到一定时候可以领取奖品,需要增加一个积分算法,构造方法有两个参数:条件和返点,让它继承CashSuper,再到收费对象生成工厂增加满100积分10点的分支条件。

这样看起来好像还是有点麻烦,简单工厂模式虽然可以解决这个问题,但这个模式只是解决对象创建问题,而且由于工厂本身包括了所有的收费方式,商场是可能经常更换促销方式,每次维护或者扩展收费方式都要改动这个工厂,以致代码需要重新编译部署。

面对算法经常变动,有更好的办法,那就是策略模式。

四、策略模式 代码3.0

在这里插入图片描述
策略模式结构图:
在这里插入图片描述
本例 中的结构图:
在这里插入图片描述
CashNormal、CashRebate、CashReturn和CashSuper不动,CashFactory暂时不用,新增一个CashContext,然后修改客户端程序。

4.1. 代码

CashContext 类:

public class CashContext {
    private CashSuper cs;
    public CashContext(CashSuper cs) {
        this.cs = cs;
    }
    public double getResult(double money){
        return cs.acceptCash(money);
    }
}

客户程序主要部分:

public class StrategyMode {
    public static void main(String[] args) {
        CashContext cashContext = null;
        String type = "打八折";
        switch (type){
            case "正常收费":
                cashContext = new CashContext(new CashNormal());
                break;
            case "打八折":
                cashContext = new CashContext(new CashRebate(0.8));
                break;
            case "满300返100":
                cashContext = new CashContext(new CashReturn(300,100));
                break;
        }
        double result = cashContext.getResult(300);
        System.out.println("最后的金额为:"+result);//240.0
    }
}

4.2. 存在的问题

策略模式使用上了,但是这个程序还是需要在客户端去判断使用哪一算法,还需要进行改进。

那么如何将这个判断过程从客户端程序移走呢?可以使用工厂模式。

简单工厂模式不一定是一个单独的类,可以和策略模式的Context结合。

五、 代码3.1 策略模式与简单工厂模式联合

5.1. 代码

改造后的CashContext 类:

public class CashContext {
    private CashSuper cs;
    //构造函数的参数不是具体的收费策略对象,而是类型
    public CashContext(String type) {
        switch (type){
            case "正常收费":
                cs = new CashNormal();
                break;
            case "打八折":
                cs = new CashRebate(0.8);
                break;
            case "满300返100":
                cs = new CashReturn(300,100);
                break;
        }
    }
    public double getResult(double money){
        return cs.acceptCash(money);
    }
}

客户程序主要部分:

public class StrategyMode {
    public static void main(String[] args) {
        CashContext cashContext = null;
        String type = "打八折";
        cashContext = new CashContext(type);
        double result = cashContext.getResult(200);
        System.out.println("最后的金额为:"+result);
    }
}

5.2. 这样做的好处

在这里插入图片描述


总结

面向对象编程并不是类越多越好,类得划分是为了封装,但分类得基础是抽象,具有相同属性和功能得对象得抽象集合才是类。

在这里插入图片描述
在开始编程时,我们
在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值