zoukankan      html  css  js  c++  java
  • 大话设计模式读书笔记(简单工厂模式)

    人物:小菜,大鸟

    事件:小菜去求职,求职题目是用Java等任意一种面向对象语言,实现一个计算机控制台程序,要求输入两个数和运算符,得到结果


    简单工厂模式:

    1.小菜实现一道面试题,输入两个数和运算符,得到结果,小菜初次实现后,大鸟指出了3个缺点

    2.小菜进行了改进,完成了功能,但思路却不是出题人的思路

    3.大鸟为了小菜更好地理解,借曹操吟诗解释了面向对象

    4.小菜尝试用封装和继承实现了简单工厂模式,最后让代码达到了灵活性好,可扩展,可复用

    小菜的初次实现

    @Slf4j
    public class Program {
        public static void main(String[] args) {
            log.info("每输入一个数字或者运算符号请敲回车");
            Scanner scanner = new Scanner(System.in);
            BigDecimal A = scanner.nextBigDecimal();
            String calculateChar = scanner.next();
            BigDecimal numberB = scanner.nextBigDecimal();
    
            if (calculateChar.equalsIgnoreCase("-")) {
                log.info(A.subtract(numberB).toString());
            }
            if (calculateChar.equalsIgnoreCase("+")) {
                log.info(A.add(numberB).toString());
            }
            if (calculateChar.equalsIgnoreCase("*")) {
                log.info(A.multiply(numberB).toString());
            }
            if (calculateChar.equalsIgnoreCase("/")) {
                log.info(A.divide(numberB).toString());
            }
        }
    }

    大鸟指出了代码缺点:

    1.第一个数字的命名不规范

    2.if...else...语句,会无用判断三次

    3.如果numberB输入的是0,则代码会报错

    小菜的再次尝试

    @Slf4j
    public class Program {
        public static void main(String[] args) {
            log.info("每输入一个数字或者运算符号请敲回车");
            Scanner scanner = new Scanner(System.in);
            BigDecimal numberA = scanner.nextBigDecimal();
            String calculateChar = scanner.next();
            BigDecimal numberB = scanner.nextBigDecimal();
            String result = "";
            try {
                switch (calculateChar) {
                    case "+":
                        result = numberA.add(numberB).toString();
                    case "-":
                        result = numberA.subtract(numberB).toString();
                    case "*":
                        result = numberA.multiply(numberB).toString();
                    case "/":
                        if (BigDecimal.ZERO.equals(numberB)) {
                            log.info("除数不能是0");
                        } else {
                            result = numberA.divide(numberB).toString();
                        }
                        break;
                }
                log.info("最后计算出的数字是:{}", result);
            } catch (Exception e) {
                log.info("输入有误,请重新输入");
            }
        }
    }

    大鸟评价:就目前来说,实现功能是没有问题了,但还需确认这样设计是否符合出题人的题意

    面向对象编程

    作者以曹操写诗,刻板,改诗,刻板,改诗,再刻板举例,改一个字,就需要全部重新刻板,而活字印刷,则改一字就重印一字即可:

    1.改字,即只需重新印刷要改之字  --可维护

    2.活体印刷这次用了,下次还可以继续使用  --可复用

    3.一篇文章若要加字,则再刻一字即可  --可拓展

    4.可改变排版格式,横排竖排都可  --灵活性好

    小菜尝试将代码复用(业务的封装)

    @Slf4j
    public class Program {
        public static void main(String[] args) {
            try {
                log.info("每输入一个数字或者运算符号请敲回车");
                Scanner scanner = new Scanner(System.in);
                BigDecimal numberA = scanner.nextBigDecimal();
                String calculateChar = scanner.next();
                BigDecimal numberB = scanner.nextBigDecimal();
                String result = getResult(numberA, numberB, calculateChar);
                if (StringUtils.isEmpty(result)) {
                    log.info("运算符请输入 + - * 或 /");
                } else {
                    log.info("最后计算出的数字是:{}", result);
                }
            } catch (Exception e) {
                log.info("输入有误,请重新输入");
            }
        }
    
        public static String getResult(BigDecimal numberA, BigDecimal numberB, String calculateChar) {
            switch (calculateChar) {
                case "+":
                    return numberA.add(numberB).toString();
                case "-":
                    return numberA.subtract(numberB).toString();
                case "*":
                    return numberA.multiply(numberB).toString();
                case "/":
                    if (BigDecimal.ZERO.equals(numberB)) {
                        log.info("除数不能是0");
                    } else {
                        return numberA.divide(numberB).toString();
                    }
                    break;
            }
            return null;
        }
    }  

    大鸟:

    业务和界面已经分离,现在已经用了面向对象三大特性之一的封装了,那么另外两个继承和多态改怎么运用到这个例子中呢?

    现在要求你加一个开根号的运算符

    小菜:

    那直接在switch上加一个开根号就行(其实以前我也是,有什么需要就加什么,完全没有考虑过设计模式的问题,使得代码很长又不好维护)

    大鸟:

    原来getResult()接口的内容被暴露了出来,增加了风险,可能不小心修改错误会导致一大片逻辑错误

    小菜尝试用继承方式实现

    @Data
    public class Operation {
        private BigDecimal numberA = BigDecimal.ZERO;
        private BigDecimal numberB = BigDecimal.ZERO;
    
        public String getResult() {
            BigDecimal result = BigDecimal.ZERO;
            return result.toString();
        }
    }
    

     将加减乘除分出来封装好(加法如下),依次继承,供以调用,如果要增加开根号,则再写一个子类即可  

    public class OperationAdd extends Operation {
        @Override
        public String getResult() {
            BigDecimal result = getNumberA().add(getNumberB());
            return result.toString();
        }
    }
    

     大鸟:思路不错,接下来就是考虑如何实例化对象的问题了,下面是简单工厂模式,可以参考解决这个问题  

    简单工厂类:

    public class OperationFactory {
        public static Operation createOperate(String operate) {
            Operation oper = null;
            switch (operate) {
                case "+":
                    oper = new OperationAdd();
                case "-":
                    //oper = new OperationSub();
                case "*":
                    //oper = new OperationMul();
                case "/":
                    //oper = new OperationDiv();
                    break;
            }
            return oper;
        }
    }
    

     客户端代码:

    public static void main(String[] args) {
            Operation oper;
            oper = OperationFactory.createOperate("+");
            oper.setNumberA(new BigDecimal("1"));
            oper.setNumberB(new BigDecimal("2"));
            String  result = oper.getResult();
            log.info("运算结果为:{}", result);
    }
    

     大鸟:就这样,只要输入运算符号,工厂就能实例化对象,通过多态,返回父类的方式得到结果  

    大鸟:编程是一门技术,更加是一门艺术,要考虑让代码更加简练,更容易维护,容易拓展和复用。

  • 相关阅读:
    qmake杂
    Qt界面风格设置
    qss使用详解
    QT数据库操作
    Qt语言家的简单使用
    c++11之右值引用和std::move
    c++11之类型萃取type_traits
    c++11之std::bind和function
    c++11之lambda
    vue中input输入框无法输入
  • 原文地址:https://www.cnblogs.com/wencheng9012/p/13362013.html
Copyright © 2011-2022 走看看