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


    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();  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    02_简单工厂模式

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

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

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

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

    工厂定义

    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;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    收银方式接口的定义

    /**  
     * 收银模式的接口  
     */  
    public interface CashSuper {  
        /**  
         * 具体的收银方法  
         */  
        Double calculateMoney(double price, int num);  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    实现类的定义

    public class Normal implements CashSuper {  
        @Override  
        public Double calculateMoney(double price, int num) {  
            return price * num;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    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;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    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;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    03_策略 + 工厂

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

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

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

    如下,之后使用者可通过 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;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    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;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    新需求实现逻辑

    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;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    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;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    public interface ICash {  
        Double calculateMoney(double price, int num);  
    }
    
    • 1
    • 2
    • 3

    将原来的 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;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    public class Normal extends CashSuper {  
        @Override  
        public Double calculateMoney(double price, int num) {  
            return super.calculateMoney(price * num, 1);  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    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;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    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;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    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;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    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 .......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    先打折,后满减

    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 .......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    提取

    # 正常销售  
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    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;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 参考
      • 《大话设计模式 Java》
  • 相关阅读:
    几个好用的数据标注软件labelme、CVAT及LabelImage
    能让你薪资翻倍的性能优化大全,大厂必问的性能调优其实很简单
    golang 组件 validator介绍以及使用案例——单字段验证和结构体验证
    2022eclipse下载安装与使用教程
    Oracle两个日期都存在返回最小/最大的,如果只存在一个就返回存在的日期
    开发知识点-Apache Axis2框架
    【uni-app】总结uni-app订单支付和打包发布
    【redis配置项-数据库通知】
    创建第一个FreeRTOS工程
    java培训之使用HttpMessageConverter
  • 原文地址:https://blog.csdn.net/qq_30763385/article/details/127765945