【设计模式】简单工厂模式

文章目录


简单工厂模式

本篇文章将为大家介绍设计模式--简单工厂模式。我们以一个简单的小计算器小程序介入。

这里我们来看初代代码:

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("请输入数字C :");
            String C  =sc.nextLine();
            double d = 0d;
            if(B.equals("+")){
                d = Double.parseDouble(A) + Double.parseDouble(C);
            }else if(B.equals("-")){
                d = Double.parseDouble(A) - Double.parseDouble(C);
            }else if(B.equals("*")){
                d= Double.parseDouble(A) * Double.parseDouble(C);
            }else if(B.equals("/")){
                d = Double.parseDouble(A) / Double.parseDouble(C);
            }
            System.out.println("结果是" + d);
        }
    }

首先针对计算器的需求,单看这个代码其实已经出现很多问题了

1.A,B,C变量命名不规范

2.用了循环的if语句判断,意味着分支需要多次判断

3.除数可能为零没有做容错判断,还有大量重复的Double.parseInt()代码。

第一版改进:

java 复制代码
  public class  Test{
        public static void main(String[] args) {
            try{
                Scanner sc = new Scanner(System.in);
                System.out.println("请输入数组A");
                Double numberA = sc.nextDouble();
                System.out.println("请输入运算符号(+,-,*,/)");
                String strOperate = sc.nextLine();
                System.out.println("请输入数字C :");
                Double numberB  =sc.nextDouble();
                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.toString());
            }
        }
    }

虽然经过修改,我们发现在解决这个问题的时候,我们都是直觉的用计算机能够理解的逻辑来描述和表达待解决的问题及具体的求解过程。这其实是用计算机的方式去思考,比如这个计算器程序,先要求输入两个数和运算符号,然后根据运算符号判断选择如何运算得到结果,这本身没有错,但这样的思维却是的我们的程序只为满足实现当前的需求,程序不容易维护,不容易扩展,更不容易复用 从而达不到高质量代码的要求。我们可以使用面向对象的编程方法去实现这个程序,来达到这些目的

1.面向对象编程

面向对象分析设计编程思想,考虑通过封装、继承、多态把程序耦合度降低。开始使用设计模式使得程序更加灵活,容易修改,并且易于复用,只有这样,我们才能逐渐体会到面向对象带来的好处,

一个好的程序是可维护的,可扩展的,可复用的、灵活性好的!

2. 复制?复用

如果这里我们需要再写一个Windows的计算器,那么现在我们的代码能不能够复用呢?

这里我们通过复制代码虽然可以,但是复制代码是非常不好的编码习惯,当你的代码中重复的代码多到一定程度,维护的时候,可能就是一场灾难。越大的系统,这种方式带来的问题就越严重,编程有一原则,就是尽可能的去避免重复,所以上述我们的计算器代码完全可以分割开来,我们思考,哪里是与控制台无关的,哪里是只和计算器有关的。

所以针对上述代码,我们可以分一个类出来,让计算和显示分开

3.业务的封装

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

代码示例:

Operation运算类:

java 复制代码
public class Operation{
      public static double Operation(double numberA,double numberB,String strOperation){
          double result  = 0d;
          switch(strOperation){
              case "+":
                  result = numberA + numberB;
                  break;
              case "-":
                  result = numberA - numberB;
                  break;
              case "*":
                  result = numberA * numberB;
                  break;
              case "/":
                  result = numberA / numberB;
                  break;
          }
          return result;
      }
  }

此时我们原来客户端的代码变成了:

java 复制代码
 public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入数组A");
        Double numberA = sc.nextDouble();
        System.out.println("请输入运算符号(+,-,*,/)");
        String strOperate = sc.nextLine();
        System.out.println("请输入数字C :");
        Double numberB  =sc.nextDouble();
        double result = Operation.getResult(numberA,numberB,strOperate);
        System.out.println("结果是 : " + result);
    }
}

经过这样的修改之后,我们将客户端代码变得更加简洁,但是这里我们仅仅使用了面向对象三大特性之一的封装,所以现在还远远谈不上面对对象。但是面对一个如此简单的程序,我们又要如何使用继承和多态呢?

4.紧耦合 松耦合

依旧以我们原来的代码为基础,我们所写的代码能否做到灵活地可修改和扩展呢?如果我们这里希望增加一个指数运算,那么我们只需要修改Operation类,在switch中多添加一个分支即可,但是要是增加一个平方根运算,却需要加减成熟的运算都得来参加编译,万一不小心,把加法变成了减法,这不就不容易维护了吗。

所以这里我们可以把加减乘除等运算分离,修改一个并不影响其他的几个,增加算法也不影响其他的代码。

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

public class Add extends Operation{
    public double getResult(double numberA,double numberB){
        return numberA + numberB;
    }
}
public class Sub extends Operation{
	public class getResult(double numberA,double numberB){
		return numberA - numberB;
	}
}
public class Mul extends Operation{
    public double getResult(double numberA,double numberB){
        return numberA * numberB;
    }
}
public class Div extends Operation{
    public double getResult(double numberA,double numberB){
        if(numberB == 0){
            System.out.println("除数不能为零");
        }
        return numberA / numberB;
    }
}

上面的代码,我们定义了一个运算抽象类,他有一个方法是getResult(numberA,numberB) 用于得到结果,之后把加减乘除都写成运算类的子类,继承他后重写getResult)()法,这样如果要修改任何一个算法,就不需要提供其他算法的代码了,问题来了,如何让计算器知道,我希望用那个算法呢?

5.简单工厂模式

代码写到上面这种程度,我们现在面临的问题是如何去实例化对象的问题,也就引出了我们的简单工厂模式,也就是说,到底要实例化谁,将来不会增加实例化的对象,比如增加指数运算,这是很容易变化的地方,应该考虑用一个单独的类来做这个创造实例的过程,这就是工厂

简单运算工厂类代码:

java 复制代码
 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 static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String strOperate = sc.next();
        int numberA = sc.nextInt(),numberB = sc.nextInt();
        Operation op = OperationFactory.createOperate(strOperate);
        double result = op.getResult(numberA,numberB);
        System.out.println(result);
    }

代码修改到这里,此时我们如果需要更改加法运算,我们只需要改Add类就可以了,如果我们需要增加各种复杂运算,比如平方根、立方根等,我们只需要增加对应的运算子类,还需要去修改运算类工厂,在switch中增加分支。

以上就是本文全部内容,本文主要以计算器这一小程序,通过不断的改进,一步一步走向面向对象编程,最后改进为简单工厂设计模式。感谢各位能够看到最后,如有问题,欢迎各位大佬在评论区指正,希望大家可以有所收获!创作不易,希望大家多多支持!

最后,大家再见!祝好!我们下期见!

相关推荐
Scott9999HH8 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔8 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社9 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海9 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖10 小时前
JDK 26 新特性详解
java·开发语言
马优晨11 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区13 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大13 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai13 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说13 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json