大话设计模式读书笔记(简单工厂模式)

人物:小菜,大鸟

事件:小菜去求职,求职题目是用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);
}

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

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

原文地址:https://www.cnblogs.com/wencheng9012/p/13362013.html