不断迭代的收银系统,工厂_策略_装饰器_反射

gitee 地址:cash_system_use_design_pattern

在这里插入图片描述
代码结构如上,建议下载,结合文章进行分析

01_不使用设计模式

不使用设计模式,完成收银系统
输入商品销售模式:1 原价 2 打折(8折) 3 满减(300 - 100)
请输入商品的销售模式
while() {
请输入商品的单价
请输入商品的数量
每次输出结果:
单价 xx 元,数量 xx 个,本次合计 xx 元
总计 xxx 元
}

public class CashSystem {  
    private Double totalPrices = 0d;  
  
    public void cashSystemMethod() {  
        System.out.println("(1)正常销售\n" + "(2)打折\n" + "(3)满减(300 - 100)");  
        System.out.println("请输入商品销售模式:");  
        int mode = Integer.parseInt(new Scanner(System.in).nextLine());  
  
        double goodPrice;  
        int goodCount;  
        do {  
            System.out.println("请输入商品的单价:");  
            goodPrice = Double.parseDouble(new Scanner(System.in).nextLine());  
            System.out.println("请输入商品的数量:");  
            goodCount = Integer.parseInt(new Scanner(System.in).nextLine());  
  
            // -----------------------------------------------------------  
            double curPrices = goodPrice * goodCount;  
  
            switch (mode) {  
                case 1:  
                    break;  
                case 2:  
                    curPrices = curPrices * 0.8;  
                    break;  
                case 3:  
                    int subTimes = (int) Math.floor(curPrices / 300);  
                    if (subTimes > 0) {  
                        curPrices = curPrices - 100 * subTimes;  
                    }  
                    break;  
                default:  
                    break;  
            }  
            // -----------------------------------------------------------  
  
            totalPrices += curPrices;  
  
            System.out.println("单价 " + goodPrice + " 元,数量 " + goodCount +  
                " 个,本次合计 " + curPrices + " 元");  
            System.out.println("总计" + totalPrices + " 元");  
        } while (goodPrice > 0 && goodCount > 0);  
    }  
  
    public static void main(String[] args) {  
        new CashSystem().cashSystemMethod();  
    }  
}

02_简单工厂模式

简单工厂与工厂模式的区别:

  • 简单工厂:工厂类 => 实例
  • 工厂模式:工厂类 => 具体工厂 => 实例

将注释 ----- 中的逻辑修改为

// -----------------------------------------------------------  
CashCalFactory cashCalFactory = new CashCalFactory(mode);  
// 从工厂中获取`收银计算的逻辑`(缺点:需知道工厂生成的`对象类型,也就是`CashSuper)  
CashSuper cashCalculate = cashCalFactory.getCashCalculate();  
// 进行计算  
Double curPrices = cashCalculate.calculateMoney(goodPrice, goodCount);  
// -----------------------------------------------------------

工厂定义

public class CashCalFactory {  
    private CashSuper cashSuper;  
    public CashCalFactory(Integer mode) {  
        switch (mode) {  
            case 1:  
                cashSuper = new Normal();  
                break;  
            case 2:  
                cashSuper = new Discount();  
                break;  
            case 3:  
                cashSuper = new FullSub();  
                break;  
            default:  
                break;  
        }  
    }  
    public CashSuper getCashCalculate() {  
        return cashSuper;  
    }  
}

收银方式接口的定义

/**  
 * 收银模式的接口  
 */  
public interface CashSuper {  
    /**  
     * 具体的收银方法  
     */  
    Double calculateMoney(double price, int num);  
}

实现类的定义

public class Normal implements CashSuper {  
    @Override  
    public Double calculateMoney(double price, int num) {  
        return price * num;  
    }  
}
public class Discount implements CashSuper {  
    private double discountRate = 0.8d;  
  
    @Override  
    public Double calculateMoney(double price, int num) {  
        return price * num * getDiscountRate();  
    }  
  
    public double getDiscountRate() {  
        return discountRate;  
    }  
  
    public void setDiscountRate(double discountRate) {  
        this.discountRate = discountRate;  
    }  
}
public class FullSub implements CashSuper {  
    private double fullCondition = 300d;  
    private double subMoney = 100d;  
  
    @Override  
    public Double calculateMoney(double price, int num) {  
        double curPrices = price * num;  
        int subTimes = (int) Math.floor(curPrices / fullCondition);  
        if (subTimes > 0) {  
            return curPrices - subMoney * subTimes;  
        }  
        return curPrices;  
    }  
  
    public void setFullCondition(double fullCondition) {  
        this.fullCondition = fullCondition;  
    }  
  
    public void setSubMoney(double subMoney) {  
        this.subMoney = subMoney;  
    }  
}

03_策略 + 工厂

策略模式,其本质在于替换:定义一个字段,通过 set 方法,对这个字段进行更新(策略上的更新)

使用策略模式,可解决工厂模式所遗留下来的问题(需要知道工厂返回的类型 SuperCash)

// -----------------------------------------------------------  
CashContext cachContext = new CashContext(mode);  
// new CashContext(mode) 之后,可直接获取结果,不需要使用者关心调用逻辑  
Double curPrices = cachContext.getResult(goodPrice, goodCount);  
// -----------------------------------------------------------

如下,之后使用者可通过 setCashSuper 方法对 cashSuper 进行替换

public class CashContext {  
    private  CashSuper cashSuper;  
  
    public CashSuper getCashCalculate() {  
        return cashSuper;  
    }  
  
    public CashContext(int mode) {  
        CashCalFactory cashCalFactory = new CashCalFactory(mode);  
        // 由上下文获取工厂生成的`对象类型`  
        cashSuper = cashCalFactory.getCashCalculate();  
    }  
  
    public Double getResult(double goodPrice, int goodCount) {  
        // 使用者可直接使用  
        return this.cashSuper.calculateMoney(goodPrice, goodCount);  
    }  
  
    public CashSuper getCashSuper() {  
        return cashSuper;  
    }  
  
    public void setCashSuper(CashSuper cashSuper) {  
        this.cashSuper = cashSuper;  
    }  
}

04_新需求,打折后,再满减

优惠大酬宾:全场8折,打折之后再满减(满 500 - 100)

public CashCalFactory(Integer mode) {  
    switch (mode) {  
        case CashMode.NORMAL:  
            cashSuper = new Normal();  
            break;  
        case CashMode.DISCOUNT:  
            cashSuper = new Discount();  
            break;  
        case CashMode.FULLSUB:  
            cashSuper = new FullSub();  
            break;  
        case CashMode.GREATEDISCOUNT:  
            // 缺点:该功能组合了 Discount 与 FullSub,存在逻辑的重复  
            cashSuper = new GreateDiscount();  
            break;  
        default:  
            break;  
    }  
}

新需求实现逻辑

public class GreateDiscount implements CashSuper {  
    private double discountRate = 0.8d;  
    private double fullCondition = 500d;  
    private double subMoney = 100d;  
  
    public Double calculateMoney(double price, int num) {  
        // 打折  
        double curPrices = price * num * getDiscountRate();  
        // 满减  
        int subTimes = (int) Math.floor(curPrices / fullCondition);  
        if (subTimes > 0) {  
            return curPrices - subMoney * subTimes;  
        }  
        return curPrices;  
    }  
  
    public double getDiscountRate() {  
        return discountRate;  
    }  
  
    public void setDiscountRate(double discountRate) {  
        this.discountRate = discountRate;  
    }  
  
    public void setFullCondition(double fullCondition) {  
        this.fullCondition = fullCondition;  
    }  
  
    public void setSubMoney(double subMoney) {  
        this.subMoney = subMoney;  
    }  
}

05_装饰器

利用装饰器,解决逻辑重复的问题

装饰的过程,相当于穿衣服(入栈操作),执行的过程,相当于脱衣服(出栈操作)

public CashCalFactory(Integer mode) {  
    switch (mode) {  
        // ......
        case CashMode.GREATEDISCOUNT:  
            Discount discount = new Discount();  
            FullSub fullSub = new FullSub();  
            // 设置满 500 - 100 的参数  
            fullSub.setFullCondition(500d);  
            fullSub.setSubMoney(100d);  
            // 调用完折扣,再调用装饰的类(满减)  
            discount.decorator(fullSub);  
            cashSuper = discount;  
            break;  
        default:  
            break;  
    }  
}
public interface ICash {  
    Double calculateMoney(double price, int num);  
}

将原来的 CashSuper 接口 变为 class,使得其子类可以进行 decorator

public class CashSuper implements ICash {  
    protected ICash component;  
  
    public void decorator(ICash component) {  
        this.component = component;  
    }  
  
    @Override  
    public Double calculateMoney(double price, int num) {  
        // 如果其子类实现了 decorator,调用  
        if (component != null) {  
            return component.calculateMoney(price, num);  
        }  
        return price;  
    }  
}
public class Normal extends CashSuper {  
    @Override  
    public Double calculateMoney(double price, int num) {  
        return super.calculateMoney(price * num, 1);  
    }  
}
public class Discount extends CashSuper {  
    private double discountRate = 0.8d;  
  
    @Override  
    public Double calculateMoney(double price, int num) {  
        double curPrices = price * num * getDiscountRate();  
        return super.calculateMoney(curPrices, 1);  
    }  
  
    public double getDiscountRate() {  
        return discountRate;  
    }  
  
    public void setDiscountRate(double discountRate) {  
        this.discountRate = discountRate;  
    }  
}
public class FullSub extends CashSuper {  
    private double fullCondition = 300d;  
    private double subMoney = 100d;  
  
    @Override  
    public Double calculateMoney(double price, int num) {  
        double curPrices = price * num;  
        int subTimes = (int) Math.floor(curPrices / fullCondition);  
        if (subTimes > 0) {  
            return super.calculateMoney(curPrices - subMoney * subTimes, 1);  
        }  
        return super.calculateMoney(curPrices, 1);  
    }  
  
    public void setFullCondition(double fullCondition) {  
        this.fullCondition = fullCondition;  
    }  
  
    public void setSubMoney(double subMoney) {  
        this.subMoney = subMoney;  
    }  
}

06_Switch 优化

利用反射的方式,对 switch 进行优化
同时,对 newInstance 的结果进行缓存

public class CashCalFactory {  
    private final CashSuper cashSuper;  
    static Map<Integer, Class<? extends CashSuper>> operationMap = new HashMap<>();  
    static Map<Class<? extends CashSuper>, CashSuper> operation_cache_map = new HashMap<>();  
  
    static {  
        operationMap.put(CashMode.NORMAL, Normal.class);  
        operationMap.put(CashMode.DISCOUNT, Discount.class);  
        operationMap.put(CashMode.FULLSUB, FullSub.class);  
        operationMap.put(CashMode.GREATEDISCOUNT, GreateDiscount.class);  
    }  
  
    public CashCalFactory(Integer mode) {  
        Class<? extends CashSuper> clazz = operationMap.get(mode);  
        CashSuper operationObject = operation_cache_map.get(clazz);  
        if (operationObject != null) {  
            cashSuper = operationObject;  
        } else {  
            try {  
                cashSuper = clazz.newInstance();  
            } catch (InstantiationException | IllegalAccessException e) {  
                throw new RuntimeException(e);  
            }  
        }  
    }  
  
    public CashSuper getCashCalculate() {  
        return cashSuper;  
    }  
}

07_新需求,满减后,再打折

变换所引起的变更,要尽可能地小

目前缺点:新增功能,需添加
(1) CashMode.FULLSUBANDDISCOUNT
(2) 添加新类:FullSubAndDiscount
(3) operationMap.put
优化方式:

  • Normal,Discount、FullSub,可统一为:先满减,后打折 以及 先打折,后满减
  • 可将逻辑提取到 data.properties 中,之后通过文件读取的方式,读取,加载即可

先满减,后打折

public class FullSubAndDiscount extends CashSuper {  
    private double discountRate = 0.8d;  
    private double fullCondition = 500d;  
    private double subMoney = 100d;  
  
    public FullSubAndDiscount(double discountRate, double fullCondition, double subMoney) {  
        this.discountRate = discountRate;  
        this.fullCondition = fullCondition;  
        this.subMoney = subMoney;  
    }  
  
    @Override  
    public Double calculateMoney(double price, int num) {  
        Discount discount = new Discount();  
        // 设置折扣  
        discount.setDiscountRate(getDiscountRate());  
        FullSub fullSub = new FullSub();  
        // 设置满减参数  
        fullSub.setFullCondition(getFullCondition());  
        fullSub.setSubMoney(getSubMoney());  
        // 调用完满减,再调用所装饰的类(折扣)  
        fullSub.decorator(discount);  
        Double result = fullSub.calculateMoney(price, num);  
        return super.calculateMoney(result, 1);  
    }
    // getter、setter .......
}

先打折,后满减

public class DisCountAndFullSub extends CashSuper {  
  
    private double discountRate = 0.8d;  
    private double fullCondition = 500d;  
    private double subMoney = 100d;  
  
    public DisCountAndFullSub(double discountRate, double fullCondition, double subMoney) {  
        this.discountRate = discountRate;  
        this.fullCondition = fullCondition;  
        this.subMoney = subMoney;  
    }  
  
    @Override  
    public Double calculateMoney(double price, int num) {  
        Discount discount = new Discount();  
        // 设置折扣  
        discount.setDiscountRate(getDiscountRate());  
        FullSub fullSub = new FullSub();  
        // 设置满减参数  
        fullSub.setFullCondition(getFullCondition());  
        fullSub.setSubMoney(getSubMoney());  
        // 调用完折扣,再调用所装饰的类(满减)  
        discount.decorator(fullSub);  
        Double result = discount.calculateMoney(price, num);  
        return super.calculateMoney(result, 1);  
    }
    // getter、setter .......
}

提取

# 正常销售  
strategy1=DisCountAndFullSub,1d,0d,0d  
# 打折  
strategy2=DisCountAndFullSub,0.8d,0d,0d  
# 满减(300 - 100)  
strategy3=DisCountAndFullSub,1d,300d,100d  
# 先打 8 折,再满减(500 - 100)  
strategy4=DisCountAndFullSub,0.8d,500d,100d  
# 先满减(500 - 100),再打 8 折  
strategy5=FullSubAndDiscount,0.8d,500d,100d

08_CashCalculateFactory 中读取参数,利用反射进行动态加载

public class CashCalculateFactory {  
    private final CashSuper cashSuper;  
    private static final String BASE_PATH = "algorithm.impl.advance";  
    static Map<String, CashSuper> operation_cache_map = new HashMap<>();  
    static List<List<String>> collect;  
  
    static {  
        Path path = Paths.get("target/classes/data.properties");  
        // 字符串处理,如:strategy1=DisCountAndFullSub,1d,0d,0d  
        Function<String, List<String>> getPropertiesFromMap = s -> {  
            String value = s.split("=")[1];  
            String[] functionAndArgs = value.split(",");  
            ArrayList<String> functionAndArgsList = new ArrayList<>();  
            functionAndArgsList.add(functionAndArgs[0]);  
            functionAndArgsList.add(functionAndArgs[1]);  
            functionAndArgsList.add(functionAndArgs[2]);  
            functionAndArgsList.add(functionAndArgs[3]);  
            return functionAndArgsList;  
        };  
        try {  
            collect = Files.readAllLines(path).stream()  
                // 过滤 # 的注释  
                .filter(v -> !"#".equals(v.substring(0, 1)))  
                .map(getPropertiesFromMap)  
                .collect(Collectors.toList());  
        } catch (IOException e) {  
            throw new RuntimeException(e);  
        }  
    }  
  
    public CashCalculateFactory(Integer mode) {  
        List<String> config = collect.get(mode - 1);  
        String functionName = config.get(0).trim();  
        String className = "cn.zhang.cash_system.fff_file_end.factory" +  
            "." +  
            BASE_PATH +  
            "." +  
            functionName;  
        if (operation_cache_map.get(className) != null) {  
            cashSuper = operation_cache_map.get(className);  
        } else {  
            try {  
                cashSuper = (CashSuper) Class.forName(className)  
                    .getDeclaredConstructor(new Class[]{double.class, double.class, double.class})  
                    .newInstance(new Object[]{  
                        Double.parseDouble(config.get(1).trim()),  
                        Double.parseDouble(config.get(2).trim()),  
                        Double.parseDouble(config.get(3).trim())  
                    });  
                operation_cache_map.put(className, cashSuper);  
            } catch (InstantiationException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException |  
                     InvocationTargetException e) {  
                throw new RuntimeException(e);  
            }  
        }  
  
    }  
  
    public CashSuper getCashCalculate() {  
        return cashSuper;  
    }  
}
  • 参考
    • 《大话设计模式 Java》
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值