背景
继我们学习了抽象出类实现开门小例子,使用事件与委托思想设计开门小例子,学习反射知识实现开门小例子,学习java中的类模板对象,手写自定义注解在经过这一系列学习后,我们终于迎来了设计模式的学习,工厂是实现23个设计模式的灵魂,所以我们要把基础打好,下面开始设计模式的学习。
过程
第一版:不使用任何工厂
图
代码:
①只使用if判断
public class Client { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入数字A"); String A =scanner.nextLine(); System.out.println("请输入数字B"); String B = scanner.nextLine(); System.out.println("请输入运算符"); String oper = scanner.nextLine(); Double result = Double.valueOf(0); //判断,这么么多if判断是否能进行优化 if(oper.equals ("+")){ result = Double.valueOf(A)+Double.valueOf(B); } if(oper.equals ("-")){ result = Double.valueOf(A)-Double.valueOf(B); } if(oper.equals("*") ){ result = Double.valueOf(A)*Double.valueOf(B); } if(oper.equals ("/")){ result = Double.valueOf(A)/Double.valueOf(B); } System.out.println(result); } }
②使用switch case
public class Client { public static void main(String[] args) { try{ Scanner scanner = new Scanner(System.in); System.out.println("请输入数字A"); int numberA= Integer.parseInt(scanner.nextLine()); System.out.println("请输入数字B"); int numberB= Integer.parseInt(scanner.nextLine()); System.out.println("请输入运算符"); String oper = scanner.nextLine(); int result = 0; //将if判断优化成switch,节省资源 switch (oper){ case "+":{ result = numberA + numberB; break; } case "-":{ result = numberA - numberB; break; } case "*":{ result = numberA * numberB; break; } case "/":{ if(numberB!==0){ result = numberA/numberB; }else{ } break; } } System.out.println("结果"+result); } }catch(Exception e){ System.out.println(e); } }
①到②的巨大变化
现象:
①优化命名规范,见名知意,增加可读性和可维护性;(将 A变成numberA 使用驼峰)
②判断除数为0以及try.catch 增加代码的健壮性,避免程序崩溃;
③多个if改为switch case 减少判断逻辑的执行,从而减少资源浪费。
革命性意义:
①从无限思维的角度想,如果后期要维护成千上万个运算,那命名不规范的话如何拓展添加,如何维护?;
②从无限思维的角度想,如果程序有上万或者上亿的if判断,每个判断都要执行,那么对于CPU资源的浪费是很多的。
③从无限思维的角度想,数是无限可能的,除数为0也是一种情况,要考虑到;并且如果用户输入的符号或者数据有问题,也会报错,
③封装了Operation类
public class Client { public static void main(String[] args) { //进行了前后端分离了 Scanner scanner= new Scanner(System.in) ; System.out.println("请输入数字A"); double numberA = Double.parseDouble(scanner.nextLine()); System.out.println("请输入数字B"); double numberB = Double.parseDouble(scanner.nextLine()); System.out.println("请输入运算符"); String operation = scanner.nextLine(); String endResult = ""; Operation oper = new Operation(); //还是将具体的逻辑暴露了出来 endResult = String.valueOf(oper.getResult(numberA,numberB,operation)); System.out.println(endResult); } }
public class Operation { public double getResult(double numberA,double numberB,String operation){ double result = 0; switch (operation){ case "+":{ result = numberA + numberB; break; } case "-":{ result = numberA - numberB; break; } case "*":{ result = numberA * numberB; break; } case "/":{ result = numberA/numberB; break; } } return result; } }
②到③的巨大变化
现象:
进行前后端分离,把客户端和后端的业务实现分离,降低前后端代码的耦合,我们可以复用后端业务代码,只需要对应修改前端的样式内容等,多端可以复用同一个后端业务。
革命意义:
用户上亿:
1、复用 (Operation 这个类),节约成本,web端,手机端。前后端可以单独部署,不用每次都部署没有改动的大部分东西。
2、便于维护,只需要改动一处。节约开发成本和维护成本。
第二版:使用简单工厂
图:
代码:
客户端代码:
public class Client { public static void main(String[] args) throws Exception { //这是创建对象的一种方式 Operation oper = null; OperationFactory operationFactory = new OperationFactory(); //下边的代码可以通过传参的方式传进来,但是我还要写四个运算类 //通过传参的形式调用加法方法 operationFactory.createOperation("+"); oper.setNumberA(1); oper.setNumberB(2); //oper 直接去执行加法算法 double result = oper.getResult(); System.out.println(result); } }
Operation类
public class Operation { private double numberA; private double numberB; public double getNumberA() { return numberA; } public void setNumberA(double numberA) { this.numberA = numberA; } public double getNumberB() { return numberB; } public void setNumberB(double numberB) { this.numberB = numberB; } public double getResult() throws Exception { double result = 0; return result; } }
此处仅使用加法运算类代替(还有减法,乘法,除法)
public class OperationAdd extends Operation{ @Override public double getResult(){ double result = 0; result = getNumberA()+ getNumberB(); return result; } }
算法工厂类
public class OperationFactory { public Operation createOperation(String operActual){ Operation operYes= null; switch (operActual){ case "+":{ operYes = new OperationAdd(); break; } case "-":{ operYes = new OperationSub(); break; } case "*":{ operYes = new OperationMul(); break; } case "/":{ operYes = new OperationDiv(); break; } } return operYes; } }
③到使用简单工厂的巨大变化
现象:
将运算的业务进行抽象、封装;抽象出一个父类,将属性和方法封装在父类,4个运算的子类,再添加新的运算类则可以直接继承父类,不影响其他的运算子类。
革命性意义:
封装、复用,符合开闭原则,这样可以减少人员维护操作带来的风险。
第三版:使用工厂方法
图:
代码:
客户端
public class Client { public static void main(String[] args) throws Exception { //父类引用指向子类对象 IFactory operFactory = new AddFactory(); //要是不能自动生成工厂的代码,这里就是脱了裤子放屁,只有在扩展的时候才有一点点用处,可以写出来符合开闭原则的代码了 Operation oper = operFactory.createOperation(); oper.setNumberA(1); oper.setNumberB(2); double result = oper.getResult(); System.out.println(result); } }
算法类
public class Operation { private double numberA; private double numberB; public double getNumberA() { return numberA; } public void setNumberA(double numberA) { this.numberA = numberA; } public double getNumberB() { return numberB; } public void setNumberB(double numberB) { this.numberB = numberB; } public double getResult() throws Exception { double result = 0; return result; } }
具体算法类
(此处只举一个加法运算类,还可以有减法运算类,乘法运算类,除法运算类):
public class OperationAdd extends Operation { @Override public double getResult(){ double result = 0; result = getNumberA()+ getNumberB(); return result; } }
工厂接口
public interface IFactory { Operation createOperation(); }
具体工厂类
(此处只举一个加法工厂类,还可以有减法工厂类,乘法工厂类,除法工厂类)
public class AddFactory implements IFactory { @Override public Operation createOperation(){ return new OperationAdd(); } }
简单工厂到工厂方法的巨大变化
现象:
①将运算工厂进行封装,从一个工厂管理四个运算子类到每个运算子类都有一个工厂进行管理。一个工厂管理一个运算类
②实现添加一个运算类同事添加一个相对应的工厂达到扩充的效果,不需要修改工厂中的代码相较于简单工厂更符合开闭原则。
③把运算类实例化对象的过程交给了工厂去完成。
革命性胜利:
当要增加一个运算的时候,完全符合开闭原则。(但是没有扩展的时候,封装这一层工厂意义不大)
于是有了下边这一版自动生成工厂代码的工厂方法。
第三版:使用工厂方法(自动化生成工厂部分代码)
①注册方式
图
代码
package twoMethodCreateClass.Register; import hotLoad.BaseManager; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Scanner; /** * @BelongsProject: JAVAtest * @BelongsPackage: hotLoad * @Author: GuoYuan.Zhao * @CreateTime: 2023-03-18 10:17 * @Description: TODO * @Version: 1.0 */ public class MyManagerHot { public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException { create(); reflect(); } static String className = ""; static String operation = ""; public static void create() throws IOException { Scanner scanner = new Scanner(System.in); System.out.println("请输入要创建的算法的模式:"); className = scanner.nextLine(); if(className.equals("Add")){ operation = "+"; }else if (className.equals("Sub")){ operation = "-"; }else if (className.equals("Mul")){ operation = "*"; }else if (className.equals("Div")){ operation = "/"; } String srcOperationCode = "package MoreAutoFactory.OperationAll;\n" + "\n" + "\n" + "import MoreAutoFactory.Operation;\n" + "\n" + "public class Operation"+className+" extends Operation {\n" + " @Override\n" + " public double getResult(){\n" + " double result = 0;\n" + " result = getNumberA()"+operation+"getNumberB();\n" + " return result;\n" + " }\n" + "\n" + "}"; //要创建文件的路径 String path1 = "E:\\zy\\TGB-zgy-2022\\米老师设计模式课相关资料必须留着\\米老师设计模式课小例子\\JAVAtest\\Factory\\src\\main\\java\\MoreAutoFactory\\OperationAll\\Operation"+ className+".java"; File file1 = new File(path1); if (!file1.exists()) { if (file1.createNewFile()) { System.out.println("新类型算法文件创建成功"); FileWriter fileWriter = new FileWriter(path1); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); bufferedWriter.write(srcOperationCode); bufferedWriter.close(); //编译文件 Compiler(System.getProperty("user.dir")+"\\Factory\\target\\classes",path1); } } String srcFactoryCode = "package MoreAutoFactory.FactoryAll;\n" + "\n" + "import MoreAutoFactory.IFactory;\n" + "import MoreAutoFactory.Operation;\n" + "import MoreAutoFactory.OperationAll.Operation"+className+";\n" + "\n" + "public class "+className+"Factory implements IFactory {\n" + " @Override\n" + " public Operation createOperation() {\n" + " return new Operation"+className+"();\n" + " }\n" + "}"; //要创建文件的路径 String path = "E:\\zy\\TGB-zgy-2022\\米老师设计模式课相关资料必须留着\\米老师设计模式课小例子\\JAVAtest\\Factory\\src\\main\\java\\MoreAutoFactory\\FactoryAll\\" + className + "Factory.java"; File file = new File(path); if (!file.exists()) { if (file.createNewFile()) { System.out.println("新类型工厂文件创建成功"); FileWriter fileWriter = new FileWriter(path); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); bufferedWriter.write(srcFactoryCode); bufferedWriter.close(); //编译文件 Compiler(System.getProperty("user.dir")+"\\Factory\\target\\classes",path); } } String srcClientCode = "package MoreAutoFactory.ClientAll;\n" + "\n" + "import MoreAutoFactory.FactoryAll."+className+"Factory;\n" + "import MoreAutoFactory.IFactory;\n" + "import MoreAutoFactory.Operation;\n" + "\n" + "public class "+className+"Client {\n" + " public void getEndResult() throws Exception {\n" + " IFactory operFactory = new "+className+"Factory();\n" + " Operation oper = operFactory.createOperation();\n" + " oper.setNumberA(2);\n" + " oper.setNumberB(2);\n" + " double result = oper.getResult();\n" + " System.out.println(result);\n" + " }\n" + "}"; //要创建文件的路径 String pathClient = "E:\\zy\\TGB-zgy-2022\\米老师设计模式课相关资料必须留着\\米老师设计模式课小例子\\JAVAtest\\Factory\\src\\main\\java\\MoreAutoFactory\\ClientAll\\" + className + "Client.java"; File fileClient = new File(pathClient); if (!fileClient.exists()) { if (fileClient.createNewFile()) { System.out.println("新类型客户端文件创建成功"); FileWriter fileWriter = new FileWriter(pathClient); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); bufferedWriter.write(srcClientCode); bufferedWriter.close(); //编译文件 Compiler(System.getProperty("user.dir")+"\\Factory\\target\\classes",pathClient); } } } public static void reflect() throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { // String str = "MoreAutoFactory.Client"+className+"Client"; // System.out.println(str); Class classClient = Class.forName("MoreAutoFactory.ClientAll."+className+"Client"); Object object = classClient.newInstance(); Method getEndResultMethod = classClient.getMethod("getEndResult"); getEndResultMethod.invoke(object,null); } public static void Compiler(String compilerPath,String javaPath){ JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); int status = javac.run(null, null, null, "-d", compilerPath,javaPath); if(status!=0){ System.out.println("没有编译成功!"); } } }
②扫描方式
图
代码
package twoMethodCreateClass.Scan; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.file.*; import java.util.*; /** * @BelongsProject: JAVAtest * @BelongsPackage: hotLoad * @Author: GuoYuan.Zhao * @CreateTime: 2023-03-18 10:17 * @Description: TODO * @Version: 1.0 */ public class MyManagerHot { static String operation = ""; public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, IOException { //首先去扫描OperationAll包下是不是多了类,如果类变多了,从类中提起关键字 如Add,然后将值赋值给变量,然后按照下面的步骤进行 String pathPackage = "E:\\zy\\TGB-zgy-2022\\米老师设计模式课相关资料必须留着\\米老师设计模式课小例子\\JAVAtest\\Factory\\src\\main\\java\\MoreAutoFactory\\OperationAll"; File file = new File(pathPackage); if (file.isDirectory()){ List<String>allNameNew = null; File[] files = file.listFiles(); for (File f : files) { String fileName = f.getAbsolutePath(); if (fileName.endsWith(".java")) { String className = fileName.substring(fileName.indexOf("MoreAutoFactory"), fileName.indexOf(".java")); String replacedName = className.replace("MoreAutoFactory\\OperationAll\\Operation", ""); // allNameNew.add(replacedName); create(replacedName); reflect(replacedName); } } } } public static void create(String className) throws IOException { Scanner scanner = new Scanner(System.in); // System.out.println("请输入要创建的算法的模式:"); // className = scanner.nextLine(); if(className.equals("Add")){ operation = "+"; }else if (className.equals("Sub")){ operation = "-"; }else if (className.equals("Mul")){ operation = "*"; }else if (className.equals("Div")){ operation = "/"; } String srcOperationCode = "package MoreAutoFactory.OperationAll;\n" + "\n" + "\n" + "import MoreAutoFactory.Operation;\n" + "\n" + "public class Operation"+className+" extends Operation {\n" + " @Override\n" + " public double getResult(){\n" + " double result = 0;\n" + " result = getNumberA()"+operation+"getNumberB();\n" + " return result;\n" + " }\n" + "\n" + "}"; //要创建文件的路径 String path1 = "E:\\zy\\TGB-zgy-2022\\米老师设计模式课相关资料必须留着\\米老师设计模式课小例子\\JAVAtest\\Factory\\src\\main\\java\\MoreAutoFactory\\OperationAll\\Operation"+ className+".java"; File file1 = new File(path1); if (!file1.exists()) { if (file1.createNewFile()) { System.out.println("新类型算法文件创建成功"); FileWriter fileWriter = new FileWriter(path1); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); bufferedWriter.write(srcOperationCode); bufferedWriter.close(); //编译文件 // Compiler(System.getProperty("user.dir")+"\\Factory\\target\\classes",path1); } } String srcFactoryCode = "package MoreAutoFactory.FactoryAll;\n" + "\n" + "import MoreAutoFactory.IFactory;\n" + "import MoreAutoFactory.Operation;\n" + "import MoreAutoFactory.OperationAll.Operation"+className+";\n" + "\n" + "public class "+className+"Factory implements IFactory {\n" + " @Override\n" + " public Operation createOperation() {\n" + " return new Operation"+className+"();\n" + " }\n" + "}"; //要创建文件的路径 String path = "E:\\zy\\TGB-zgy-2022\\米老师设计模式课相关资料必须留着\\米老师设计模式课小例子\\JAVAtest\\Factory\\src\\main\\java\\MoreAutoFactory\\FactoryAll\\" + className + "Factory.java"; File file = new File(path); if (!file.exists()) { if (file.createNewFile()) { System.out.println("新类型工厂文件创建成功"); FileWriter fileWriter = new FileWriter(path); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); bufferedWriter.write(srcFactoryCode); bufferedWriter.close(); //编译文件 // Compiler(System.getProperty("user.dir")+"\\Factory\\target\\classes",path); } } String srcClientCode = "package MoreAutoFactory.ClientAll;\n" + "\n" + "import MoreAutoFactory.FactoryAll."+className+"Factory;\n" + "import MoreAutoFactory.IFactory;\n" + "import MoreAutoFactory.Operation;\n" + "\n" + "public class "+className+"Client {\n" + " public void getEndResult() throws Exception {\n" + " IFactory operFactory = new "+className+"Factory();\n" + " Operation oper = operFactory.createOperation();\n" + " oper.setNumberA(2);\n" + " oper.setNumberB(2);\n" + " double result = oper.getResult();\n" + // " System.out.println("+className+");\n" + " System.out.println(result);\n" + " }\n" + "}"; //要创建文件的路径 String pathClient = "E:\\zy\\TGB-zgy-2022\\米老师设计模式课相关资料必须留着\\米老师设计模式课小例子\\JAVAtest\\Factory\\src\\main\\java\\MoreAutoFactory\\ClientAll\\" + className + "Client.java"; File fileClient = new File(pathClient); if (!fileClient.exists()) { if (fileClient.createNewFile()) { System.out.println("新类型客户端文件创建成功"); FileWriter fileWriter = new FileWriter(pathClient); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); bufferedWriter.write(srcClientCode); bufferedWriter.close(); //编译文件 // Compiler(System.getProperty("user.dir")+"\\Factory\\target\\classes",pathClient); } } } public static void reflect(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { // String str = "MoreAutoFactory.Client"+className+"Client"; // System.out.println(str); Class classClient = Class.forName("MoreAutoFactory.ClientAll."+className+"Client"); Object object = classClient.newInstance(); Method getEndResultMethod = classClient.getMethod("getEndResult"); getEndResultMethod.invoke(object,null); } public static void Compiler(String compilerPath,String javaPath){ JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); int status = javac.run(null, null, null, "-d", compilerPath,javaPath); if(status!=0){ System.out.println("没有编译成功!"); } } }
自动生成工厂部分代码的工厂方法巨大意义:
让软件的使用者成为软件使用者,将所有的权利给用户了,我们的系统不需要人维护,节约了巨大的成本。(想一想维护原来的代码有多么麻烦,现在这个工作可以交给用户了)
总结
不管是面向过程,还是面向函数,还是面向对象编程,都只是一种设计思想,没有好坏之分,使用面向对象的思想设计我们的系统维护起来更方便。 拿工厂这一步步的变化来说,我发现我们都是要以人为本,这个人可以是开发人员,也可以是系统的使用者,比如,开始一版的时候我们着眼于开发人员,我们希望我们写的代码能让开发人员读代码更方便,所以我们要规范命名,再到后来的加trycatch,是为了方便开发人员捕获异常然后进行处理,同时不会让系统崩溃,给用户造成困扰。还是在代码里边写除数不能为0是为了更符合用户的认知,后来使用工厂也是为了符合开闭原则,还是为了防止开发人员改错代码带来不可控的损失,直到我们设计出直接根据前端传过来的参数直接生成类,编译运行。我们才把所有的权限真正交给了用户,与此同时,大大减少雇佣的程序维护人员的巨大成本。一箭双雕~