• 聊聊设计模式--简单工厂模式


    简单工厂模式

    ​ 前面也学了很多各种微服务架构的组件,包括后续的服务部署、代码管理、Docker等技术,那么作为后端人员,最重要的任务还是代码编写能力,如何让你的代码写的漂亮、易扩展,让别人一看赏心悦目,那么设计模式就是很重的了。那么本本篇文章就来聊聊一个简单的工厂模式。

    缘起

    ​ 一个22岁刚毕业的大学生A,计算机专业学的Java语言,到B公司面试。而面试题非常简单,实现一个简易计算器的功能,A觉得面试题很简单,三下五除二直接10分钟完事儿了。然而交卷后,迟迟等不到B公司的通知,多半是凉了,那么他是怎么实现的呢?代码如下:

    public class Test {
    
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入数字A:");
            String A = sc.nextLine();
            System.out.println("请选择运算符(+、-、*、/):");
            String B = sc.nextLine();
            System.out.println("请输入数字B:");
            String C = sc.nextLine();
            double D = 0d;
            
            if (B.equals("+")) D = Double.parseDouble(A) + Double.parseDouble(C);
            if (B.equals("-")) D = Double.parseDouble(A) - Double.parseDouble(C);
            if (B.equals("*")) D = Double.parseDouble(A) * Double.parseDouble(C);
            if (B.equals("/")) D = Double.parseDouble(A) / Double.parseDouble(C);
    
            System.out.println("结果是:" + D);
    
        }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    那么就以上的代码,按功能来说,有问题吗?

    没问题,功能确实实现了;但是细看就会发现代码规范及其他的问题:

    • 变量名命名问题:ABCD?
    • if判断问题,假如输入的是+号,那么其他的判断还有必要再去执行吗,没必要
    • 输入的不是数字时怎么处理

    那么按照上面的问题,依次去改动代码

    public class Test {
    
        public static void main(String[] args) {
            try {
                Scanner sc = new Scanner(System.in);
                System.out.println("请输入数字A:");
                double numberA = Double.parseDouble(sc.nextLine());
                System.out.println("请选择运算符(+、-、*、/):");
                String strOperate = sc.nextLine();
                System.out.println("请输入数字B:");
                double numberB = Double.parseDouble(sc.nextLine());
                double result = 0d;
                switch (strOperate) {
                    case "+":
                        result = numberA + numberB;
                        break;
                    case "-":
                        result = numberA - numberB;
                        break;
                    case "*":
                        result = numberA * numberB;
                        break;
                    case "/":
                        result = numberA / numberB;
                        break;
                }
                System.out.println("结果是:" + result);
            } catch (Exception e) {
                System.out.println("您的输入有误:" + e.getMessage());
            }
        }
    
    }
    
    • 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

    行了,代码规范的问题是都已经完善了。

    那么如何提高代码的可维护、可扩展、可复用、灵活性更好呢?

    答案就是面向对象。

    业务的封装

    准确的说,就是让业务逻辑和界面逻辑分开,让它们之间的耦合度下降,只有分离开,才可以达到容易维护和扩展。

    增加一个运算类

    public class Operation {
        
        public static double getResult(double numberA, double numberB, String operate) {
            double result = 0d;
            switch (operate) {
                case "+":
                    result = numberA + numberB;
                    break;
                case "-":
                    result = numberA - numberB;
                    break;
                case "*":
                    result = numberA * numberB;
                    break;
                case "/":
                    result = numberA / numberB;
                    break;
            }
            return result;
        }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    那么客户端Test的代码

    public class Test {
    
        public static void main(String[] args) {
            try {
                Scanner sc = new Scanner(System.in);
                System.out.println("请输入数字A:");
                double numberA = Double.parseDouble(sc.nextLine());
                System.out.println("请选择运算符(+、-、*、/):");
                String strOperate = sc.nextLine();
                System.out.println("请输入数字B:");
                double numberB = Double.parseDouble(sc.nextLine());
                double result = Operation.getResult(numberA, numberB, strOperate);
                System.out.println("结果是:" + result);
            } catch (Exception e) {
                System.out.println("您的输入有误:" + e.getMessage());
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    业务逻辑和界面逻辑都分离开了,那么这种方案就是面向对象的封装,三大特性之一。

    增加功能

    计算器的功能发生改变了,不仅要支持+-*/,我还想要加一个平方根运算,那我们就需要去修改Operation类中的代码

    public class Operation {
    
        public static double getResult(double numberA, double numberB, String operate) {
            double result = 0d;
            switch (operate) {
                case "+":
                    result = numberA + numberB;
                    break;
                case "-":
                    result = numberA - numberB;
                    break;
                case "*":
                    result = numberA * numberB;
                    break;
                case "/":
                    result = numberA / numberB;
                    break;
                case "pow":
                    result = Math.pow(numberA, numberB);
                    break;
            }
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    那么问题来了,我这里是加了一个pow的case分支,加一个平方根运算的功能,但是却需要让加减乘除的运算全都得来参与编译,万一一个不小心,把加法运算改成减法了,又没有注意到,直接给上生产环境了,这之后造成的问题能承担的了吗?

    那么我们为了增加功能,而不让其他已经存在的功能有代码误改的风险。继续对业务方法进行改进.

    我们将Operation类置为抽象类,让其他的加减乘除继承它,并且每一个功能都是一个单独的类实现自己的业务逻辑

    public abstract class Operation {
        public double getResult(double numberA, double numberB) {
            return 0d;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    加减乘除类

    public class Add extends Operation { // 加
        @Override
        public double getResult(double numberA, double numberB) {
            return numberA + numberB;
        }
    }
    
    public class Sub extends Operation { // 减
        @Override
        public double getResult(double numberA, double numberB) {
            return numberA - numberB;
        }
    }
    
    public class Mul extends Operation { // 乘
        @Override
        public double getResult(double numberA, double numberB) {
            return numberA * numberB;
        }
    }
    
    public class Div extends Operation { // 除
        @Override
        public double getResult(double numberA, double numberB) {
            if (numberB == 0) {
                System.out.println("除数不能为0");
                throw new RuntimeException();
            }
            return numberA / numberB;
        }
    }
    
    • 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

    实现简单工厂

    上面抽象出来一个操作类(Operation),并且有加减乘除的业务逻辑类,那么我如何得知,应该用哪个业务逻辑类呢?

    这时候,我们就需要一个工厂类,工厂顾名思义就是用来加工的,我把原料放进去,工厂给我生产出来产品。

    public class OperationFactory {  
        public static Operation createOperate(String operate) {
            Operation oper = null;
            switch (operate) {
                case "+":
                    oper = new Add();
                    break;
                case "-":
                    oper = new Sub();
                    break;
                case "*":
                    oper = new Mul();
                    break;
                case "/":
                    oper = new Div();
                    break;
            }
            return oper;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    客户端这里调用时

    public class Test {
    
        public static void main(String[] args) {
            try {
                Scanner sc = new Scanner(System.in);
                System.out.println("请输入数字A:");
                double numberA = Double.parseDouble(sc.nextLine());
                System.out.println("请选择运算符(+、-、*、/):");
                String strOperate = sc.nextLine();
                System.out.println("请输入数字B:");
                double numberB = Double.parseDouble(sc.nextLine());
                Operation operate = OperationFactory.createOperate(strOperate);
                double result = operate.getResult(numberA, numberB);
                System.out.println("结果是:" + result);
            } catch (Exception e) {
                System.out.println("您的输入有误:" + e.getMessage());
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    上面就是大致的结构图,当我们再次增加新的功能时,只需要去集成Operation运算类,然后实现自己的业务逻辑就可以了,看起来是不是比原先的一坨代码更加一目了然了,并且也提高了它的复用性、维护性、扩展性,也更加灵活了。

  • 相关阅读:
    C++小练习:字符串分割的高性能实现
    树形结构通用工具类
    Day698.Tomcat的日志框架及实战 -深入拆解 Tomcat & Jetty
    Python 3.6.10 中的 requests 库 TLS 1.2 强制使用问题及解决方案
    处理一些数据
    make: /bin/nvcc: Command not found 解决找不到nvcc
    【板栗糖GIS】DOS—如何删除特定的文件夹
    DP - OOD - SRP
    echarts 中如何添加左右滚动条 数据如何进行堆叠如何配置那些数据使用那个数据轴
    nodejs+vue健身服务应用elementui
  • 原文地址:https://blog.csdn.net/weixin_45248492/article/details/133958750