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

简单工厂模式

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

缘起

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

java 复制代码
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);

    }
    
}

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

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

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

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

java 复制代码
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());
        }
    }

}

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

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

答案就是面向对象。

业务的封装

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

增加一个运算类

java 复制代码
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;
    }
    
}

那么客户端Test的代码

java 复制代码
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());
        }
    }

}

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

增加功能

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

java 复制代码
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;
    }
}

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

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

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

java 复制代码
public abstract class Operation {
    public double getResult(double numberA, double numberB) {
        return 0d;
    }
}

加减乘除类

java 复制代码
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;
    }
}

实现简单工厂

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

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

java 复制代码
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;
    }
}

客户端这里调用时

java 复制代码
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());
        }
    }

}

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

相关推荐
Boilermaker19924 小时前
[Java 并发编程] Synchronized 锁升级
java·开发语言
Cherry的跨界思维5 小时前
28、AI测试环境搭建与全栈工具实战:从本地到云平台的完整指南
java·人工智能·vue3·ai测试·ai全栈·测试全栈·ai测试全栈
alonewolf_995 小时前
JDK17新特性全面解析:从语法革新到模块化革命
java·开发语言·jvm·jdk
一嘴一个橘子5 小时前
spring-aop 的 基础使用(啥是增强类、切点、切面)- 2
java
sheji34165 小时前
【开题答辩全过程】以 中医药文化科普系统为例,包含答辩的问题和答案
java
恋爱绝缘体16 小时前
2020重学C++重构你的C++知识体系
java·开发语言·c++·算法·junit
xiaolyuh1236 小时前
Spring 框架 核心架构设计 深度详解
spring·设计模式·spring 设计模式
wszy18096 小时前
新文章标签:让用户一眼发现最新内容
java·python·harmonyos
wszy18097 小时前
顶部标题栏的设计与实现:让用户知道自己在哪
java·python·react native·harmonyos
程序员小假7 小时前
我们来说一下无锁队列 Disruptor 的原理
java·后端