目录
一、背景介绍
二、阶段分析
没有使用工厂:P1、P2
需求
实现
总结
从没有使用工厂到进行了前后端分离P1、2-P3
需求
实现
总结
从前后端分离到简单工厂P3-P9、P10
需求
实现
总结
从简单工厂到工厂方法P10、11-P69、70
需求
实现
总结
从工厂方法到工厂类由程序来创建
需求
实现
扫描版本
注册版本
总结
从自动创建类到热加载创建的类
需求
实现
总结
一、背景介绍
相信大家都学过设计模式,对于简单工厂、工厂方法和抽象工厂都听说过,也知道怎么用。但是从没有工厂到添加了工厂到工厂方法再到抽象工厂每一次的巨大的变化和给我们以及用户带来了哪些好处是我们不清楚的,下面我们来一起分析每一次变换的重大意义以及到工厂方法之后如何体现我们的想象力和创造力。
二、阶段分析
注:Px 代表设计模式书上的页码
没有使用工厂:P1、P2
需求
实现一个简单的计算器例子
实现
客户端
public class Client {
public static void main(String[] args) throws IOException {
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入要计算的第一个数字");
String A = br.readLine();
System.out.println("请选择运算符号(+、-、*、/)");
String strOperate = br.readLine();
System.out.println("请输入要计算的第二个数字");
String B = br.readLine();
String NumberSum="";
if (strOperate.equals("+")){
NumberSum=String.valueOf(Double.valueOf(A) +Double.valueOf(B));
}
if (strOperate.equals("-")){
NumberSum=String.valueOf(Double.valueOf(A) -Double.valueOf(B));
}
if (strOperate.equals("*")){
NumberSum=String.valueOf(Double.valueOf(A) *Double.valueOf(B));
}
if (strOperate.equals("/")){
NumberSum=String.valueOf(Double.valueOf(A) /Double.valueOf(B));
}
System.out.println("没使用工厂第一版的结果:"+NumberSum);
}
}
运行结果
总结
单纯的实现了一个加减乘除的计算机小例子,通过控制台输入数据和运算符的方式进行运算。没有应用开发规范和一些设计的思想。把功能的样式(控制台的提示和输入的内容)和功能的业务逻辑写在了一起。
从没有使用工厂到进行了前后端分离P1、2-P3
需求
编写一个不同端的系统,代码如何复用。比如已经在pc端写好了一个计算器例子,再写一个手机端的是不是可以复用代码。
实现
客户端
public class Client {
public static void main(String[] args) {
try{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入要计算的第一个数字");
String strNumberA = br.readLine();
System.out.println("请选择运算符号(+、-、*、/)");
String strOperate = br.readLine();
System.out.println("请输入要计算的第二个数字");
String strNumberB = br.readLine();
Double strResult= Operation.getResult(Double.valueOf(strNumberA), Double.valueOf(strNumberB),strOperate);
System.out.println("结果是:"+strResult);
} catch (IOException e) {
e.printStackTrace();
}
}
}
运算类
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 "/":
if (numberB==0){
System.out.println("除数不能为0");
}else{
result=numberA/numberB;
}
break;
}
return result;
}
}
运行结果
总结
1、调整了命名规范:没有命名格式到驼峰命名格式。
2、进行了前后端分离:把功能样式和功能具体逻辑写到一起到把功能具体逻辑封装到一个类中(Operation)。达到了前后端分离,后端的业务逻辑可以进行复用。多个前端都可以调用同一个后端。降低了功能样式和功能业务逻辑的耦合。
3、考虑了报错的情况:在除法中没有对除数进行判断到判断是否0,增加了程序的健壮性。
4、把四个并列的if换成了switch case:减少了资源的浪费,从四个运算中选择一个运算只需要判断一次就可以不需要每种情况进行判断,如果判断的类型非常多的话会造成cpu飙升的问题。
5、减少了报错的情况增强了用户的体验感。 前后端分离减少了开发成本代码直接复用即可。 命名规范提高了开发的效率不用去猜这个变量是干什么的
从前后端分离到简单工厂P3-P9、P10
需求
添加一个新的运算类不会影响其他的运算类
实现
结构
客户端
public class Client {
public static void main(String[] args) throws Exception {
Operation operation;
operation=OperationFactory.createOperate("+");
operation.setNumberA(1);
operation.setNumberB(2);
double result=operation.getResult();
System.out.println("简单工厂的运行结果:"+result);
}
}
运算工厂
public class OperationFactory {
public static Operation createOperate(String operate) {
Operation operation=null;
switch (operate){
case"+":
operation=new OperationAdd();
break;
case"-":
operation=new OperationSub();
break;
case"*":
operation=new OperationMul();
break;
case"/":
operation=new OperationDiv();
break;
}
return operation;
}
}
运算父类
@Data
public class Operation {
private double numberA=0;
private double numberB=0;
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 OperationDiv extends Operation{
@Override
public double getResult() throws Exception {
double result=0;
if(getNumberB()==0){
throw new Exception("除数不能为0");
}
result=getNumberA()/getNumberB();
return result;
}
}
运行结果
总结
1、将四种运算方式进行了封装:把直接在Operation进行计算到四种运算都写成了类,抽象了运算父类,以后添加其他业务直接继承运算父类即可达到扩充的效果。
2、把要调用的运算类写死在了客户端中,缺少了和用户之间的交互。可以通过让用户输入的方式去实例化对应的运算类。完成对应的运算结果。
3、把四种运算进行封装,避免了开发人员因添加一个运算修改了其他运算的情况,增加了代码的安全性。对于运算类的扩充直接继承父类
从简单工厂到工厂方法P10、11-P69、70
需求
在添加新的运算类的时候符合开闭原则,不需要在OperationFactory中修改代码。
实现
结构
客户端
public class Client {
public static void main(String[] args) throws Exception {
IFactory operFactory=new AddFactory();
Operation operation = operFactory.createOperation();
operation.setNumberA(1);
operation.setNumberB(2);
double result=operation.getResult();
System.out.println("工厂方法的运行结果:"+result);
}
}
运算父类
@Data
public class Operation {
private double numberA=0;
private double numberB=0;
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();
}
}
运行结果
总结
1、将工厂进行了拆分:从一个工厂管理四个运算子类到每个运算子类都有一个工厂进行管理。添加一个运算类在添加一个相对应的工厂达到扩充的效果,不需要修改工厂中的代码相较于简单工厂更符合开闭原则。一个工厂只负责一件事情。
2、把实例化对象的过程交给了工厂去完成。
从工厂方法到工厂类由程序来创建
需求
把重复性有规律性的内容交给程序去完成,提高了开发人员的工作效率。 减少了人为操作出错的情况。
实现
扫描版本
结构
客户端
package AutomaticCreateFactory;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @BelongsProject: DesignPattern
* @BelongsPackage: AutomaticCreateFactory
* @Author: Wuzilong
* @Description: 生成工厂类
* @CreateTime: 2023-03-15 16:57
* @Version: 1.0
*/
public class CreateClass {
public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException {
// 工厂文件模板
String factoryTemplate = "D://项目//设计模式//Java//DesignPattern//src//main//java//AutomaticCreateFactory//FactoryTemplate";
//客户端文件模板
String clientTemplate ="D://项目//设计模式//Java//DesignPattern//src//main//java//AutomaticCreateFactory//ClientTemplate";
//运算子类的抽象类名
String className = "FactoryTemplate";
//运算子类中要实例化的类的抽象类名
String reClass="OperationClass";
//客户端的抽象类名
String clientName="Client";
//客户端中要实例化的类的抽象类名
String newName="OperationFactory";
//创建工厂的方法
createClass(factoryTemplate,className,reClass);
//创建客户端的方法
createClass(clientTemplate,clientName,newName);
}
private static void createClass(String filePath,String className,String reClass) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException, IOException {
String packagePath="D://项目//设计模式//Java//DesignPattern//src//main//java//AutomaticCreateFactory//OperClass//";
//反射的类路径
String[] classPath=new String[4];
//要创建的java类的名字
String[] target =new String[4];
File file = new File(packagePath);
//判断是不是文件夹
if (file.isDirectory()){
File[] files = file.listFiles();
for (int i=0; i<files.length;i++){
String fileNamePath=files[i].getAbsolutePath();
if (files[i].getAbsolutePath().endsWith(".java")){
String operClassPath = fileNamePath.substring(fileNamePath.indexOf("OperClass"), fileNamePath.indexOf(".java"));
String createClassName = operClassPath.replace("OperClass\\", "");
target[i]=createClassName;
classPath[i]="AutomaticCreateFactory.OperClass."+createClassName;
}
}
}
// 创建java类的存放路径
String targetURL = "D://项目//设计模式//Java//DesignPattern//src//main//java//AutomaticCreateFactory//OperFactory//";
//存放class文件的路径
String classURL="D://项目//设计模式//Java//DesignPattern//target//classes//";
int isClient=0;
for (int i = 0; i < target.length; i++) {
try {
BufferedReader bufReader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)));//数据流读取文件
//StringBuffer动态的字符串数组
StringBuffer strBuffer = new StringBuffer();
//截取计算类的后三位
String substring = target[i].substring(target[i].length() - 3);
String classNameStr=substring+"Factory";
for (String temp = null; (temp = bufReader.readLine()) != null; temp = null) {
//判断当前行是否存在想要替换掉的字符
if(temp.contains(className)){
if (className.contains("Client")){
//替换类名
temp = temp.replace(className, classNameStr+"Client");
}else{
//替换类名
temp = temp.replace(className, classNameStr);
}
}else if(temp.contains(reClass)){
if (reClass.contains("Factory")){
//替换返回需要实例化的类名
temp = temp.replace(reClass, classNameStr);
isClient+=1;
}else{
//反射获取计算类的名称
Class classObject = Class.forName(classPath[i]);
//替换返回需要实例化的类名
temp=temp.replace(reClass, classObject.getSimpleName());
}
}
//把读取的每一行添加到数组中
strBuffer.append(temp);
//换行符
strBuffer.append(System.getProperty("line.separator"));
}
bufReader.close();
PrintWriter printWriter = null;
String createClassName=null;
if (isClient>0){
//创建java对象并存放在对应的路径当中
printWriter = new PrintWriter(targetURL+classNameStr+"Client"+".java");
createClassName=targetURL+ classNameStr+"Client"+".java";
}else{
printWriter = new PrintWriter(targetURL+classNameStr+".java");
createClassName=targetURL+ classNameStr+".java";
}
//将获取数据的数组写入到创建的java对象中
printWriter.write(strBuffer.toString().toCharArray());
printWriter.flush();
printWriter.close();
Compiler compiler = new Compiler();
compiler.compiler(classURL,createClassName);
} catch (Exception e) {
e.printStackTrace();
}
}
if (isClient==4){
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入要执行的算法类");
String operation = br.readLine();
Class aClass = Class.forName("AutomaticCreateFactory.OperFactory." + operation + "Client");
Object object = aClass.newInstance();
Method mainMethod = aClass.getMethod("main");
mainMethod.invoke(object);
}
}
}
编译文件类:将java文件编译成class文件
public class Compiler extends ClassLoader {
public 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 AutomaticCreateFactoryV3;
import java.io.*;
import java.lang.reflect.Method;
/**
* @BelongsProject: DesignPattern
* @BelongsPackage: AutomaticCreateFactory
* @Author: Wuzilong
* @Description: 描述什么人干什么事儿
* @CreateTime: 2023-03-15 16:57
* @Version: 1.0
*/
public class CreateClass {
public static void main(String[] args) throws IOException {
//公共路径
String commonPath="D://项目//设计模式//Java//DesignPattern//src//main//java//AutomaticCreateFactoryV3//Template//";
// 工厂文件模板
String factoryTemplate = commonPath+"FactoryTemplate";
//客户端文件模板
String clientTemplate = commonPath+"ClientTemplate";
//运算子类的模板
String operationTemplate = commonPath+"OperationTemplate";
//运算类的名称
String operClassName="OperationName";
//运算类的符号
String operClassSign="?";
//工厂中运算子类的抽象类名
String className = "FactoryTemplate";
//工厂中运算子类中要实例化的类的抽象类名
String reClass = "OperationClass";
//客户端的抽象类名
String clientName = "Client";
//客户端中要实例化的类的抽象类名
String newName = "OperFactory";
//创建运算子类的方法
createFile(operationTemplate,operClassName,operClassSign);
//创建工厂的方法
createFile(factoryTemplate, className, reClass);
//创建客户端的方法
createFile(clientTemplate, clientName, newName);
}
private static void createFile(String filePath, String className, String reClass) throws IOException {
// 创建java类的存放路径
String javaURL = "D://项目//设计模式//Java//DesignPattern//src//main//java//AutomaticCreateFactoryV3//OperationFactory//";
String operationClassURL = "D://项目//设计模式//Java//DesignPattern//src//main//java//AutomaticCreateFactoryV3//OperationSubclass//";
String classURL="D://项目//设计模式//Java//DesignPattern//target//classes//";
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
Boolean isShow=false;
System.out.println("请输入要创建的类名");
String createClassName = br.readLine();
try {
BufferedReader bufReader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)));//数据流读取文件
//StringBuffer动态的字符串数组
StringBuffer strBuffer = new StringBuffer();
for (String temp = null; (temp = bufReader.readLine()) != null; temp = null) {
//判断当前行是否存在想要替换掉的字符
if (temp.contains(className)) {
//替换类名
temp = temp.replace(className, createClassName);
} else if (temp.contains(reClass)) {
if (reClass.contains("Factory")) {
String classNameStr = createClassName.substring(0, 10);
//替换返回需要实例化的类名
temp = temp.replace(reClass, classNameStr);
}else if(createClassName.contains("Operation")){
isShow=true;
if (createClassName.contains("OperationAdd")){
temp=temp.replace(reClass, "+");
}else if(createClassName.contains("OperationSub")){
temp=temp.replace(reClass, "-");
}else if(createClassName.contains("OperationMul")){
temp=temp.replace(reClass, "*");
}else{
temp=temp.replace(reClass, "/");
}
}else {
//反射获取计算类的名称
String classStr = createClassName.substring(0, 3);
Class classObject = Class.forName("AutomaticCreateFactoryV3.OperationSubclass.Operation"+classStr);
//替换返回需要实例化的类名
temp = temp.replace(reClass, classObject.getSimpleName());
}
}
//把读取的每一行添加到数组中
strBuffer.append(temp);
//换行符
strBuffer.append(System.getProperty("line.separator"));
}
bufReader.close();
//创建java对象并存放在对应的路径当中
PrintWriter printWriter = null;
String classFilePath="";
String compileClassName="";
if (isShow){
printWriter=new PrintWriter(operationClassURL+createClassName+".java");
classFilePath=classURL+"AutomaticCreateFactoryV3//OperationSubclass//"+createClassName+".class";
compileClassName="AutomaticCreateFactoryV3.OperationSubclass."+createClassName;
}else{
printWriter=new PrintWriter(javaURL + createClassName + ".java");
classFilePath=classURL+"AutomaticCreateFactoryV3//OperationFactory//"+createClassName+".class";
compileClassName="AutomaticCreateFactoryV3.OperationFactory."+createClassName;
}
//将获取数据的数组写入到创建的java对象中
printWriter.write(strBuffer.toString().toCharArray());
printWriter.flush();
printWriter.close();
//调用一个编译源码的方法,将创建出的.java文件编译成.class文件
Compiler compiler = new Compiler();
String srcFilePath =javaURL+createClassName+".java";
if (isShow){
compiler.compiler(classURL,operationClassURL+createClassName+".java");
}else{
compiler.compiler(classURL,srcFilePath);
}
Class<?> aClass = compiler.findClass(compileClassName, classFilePath);
Object instance = aClass.getConstructor().newInstance();
if (createClassName.contains("Client")){
Method createMethod = aClass.getMethod("createMethod");
createMethod.invoke(instance);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
运算类模板
工厂类模板
运行结果
总结
我们能完成的事情系统也能完成。将重复性的代码让系统替我们来完成,我们来完成具有想象力和创造力的事情。这样提高了我们的开发效率,也减少了出错的情况。随着业务越来越多我们自动生成的也就越来越多。从一开的只写一个变成了后来的无数多个。
从自动创建类到热加载创建的类
需求
程序运行的过程中添加一个类也同样可以执行运算结果,不需要把程序重启
实现
结构
客户端
public class Logon {
public static void main(String[] args) {
Regular regular=new Regular();
regular.run();
}
}
定时扫描器
public class Regular implements Runnable{
public void run() {
CreateClass createClass=new CreateClass();
// 需要定时执行的任务
Runnable runnable = () -> {
try {
createClass.createClass();
} catch (Exception e) {
throw new RuntimeException(e);
}
};
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
//立即执行,并且每5秒执行一次
ses.scheduleAtFixedRate(runnable, 0, 15000, TimeUnit.MILLISECONDS);
}
}
package AutomaticCreateFactoryV4;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* @BelongsProject: DesignPattern
* @BelongsPackage: AutomaticCreateFactory
* @Author: Wuzilong
* @Description: 描述什么人干什么事儿
* @CreateTime: 2023-03-15 16:57
* @Version: 1.0
*/
public class CreateClass {
public void createClass() throws IOException, ClassNotFoundException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException {
// 工厂文件模板
String factoryTemplate = "D://项目//设计模式//Java//DesignPattern//src//main//java//AutomaticCreateFactoryV4//FactoryTemplate";
//客户端文件模板
String clientTemplate ="D://项目//设计模式//Java//DesignPattern//src//main//java//AutomaticCreateFactoryV4//ClientTemplate";
//运算子类的抽象类名
String className = "FactoryTemplate";
//运算子类中要实例化的类的抽象类名
String reClass="OperationClass";
//客户端的抽象类名
String clientName="Client";
//客户端中要实例化的类的抽象类名
String newName="OperationFactory";
//创建工厂的方法
createFlie(factoryTemplate,className,reClass);
//创建客户端的方法
createFlie(clientTemplate,clientName,newName);
}
private static void createFlie(String filePath,String className,String reClass) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException, IOException {
String packagePath="D://项目//设计模式//Java//DesignPattern//src//main//java//AutomaticCreateFactoryV4//OperClass//";
//反射的类路径
List<String> classPath=new ArrayList();
//要创建的java类的名字
List<String> target=new ArrayList<>();
File file = new File(packagePath);
//判断是不是文件夹
if (file.isDirectory()){
File[] files = file.listFiles();
for (int i=0; i<files.length;i++){
String fileNamePath=files[i].getAbsolutePath();
if (files[i].getAbsolutePath().endsWith(".java")){
String operClassPath = fileNamePath.substring(fileNamePath.indexOf("OperClass"), fileNamePath.indexOf(".java"));
String createClassName = operClassPath.replace("OperClass\\", "");
target.add(createClassName);
classPath.add("AutomaticCreateFactoryV4.OperClass."+createClassName);
}
}
}
// 创建java类的存放路径
String targetURL = "D://项目//设计模式//Java//DesignPattern//src//main//java//AutomaticCreateFactoryV4//OperFactory//";
//存放class文件的路径
String classURL="D://项目//设计模式//Java//DesignPattern//target//classes//";
int isClient=0;
for (int i = 0; i < target.size(); i++) {
try {
BufferedReader bufReader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)));//数据流读取文件
//StringBuffer动态的字符串数组
StringBuffer strBuffer = new StringBuffer();
//将java编译成class的类
Compiler compiler = new Compiler();
//截取计算类的后三位
String substring = target.get(i).substring(target.get(i).length() - 3);
String classNameStr=substring+"Factory";
for (String temp = null; (temp = bufReader.readLine()) != null; temp = null) {
//判断当前行是否存在想要替换掉的字符
if(temp.contains(className)){
if (className.contains("Client")){
//替换类名
temp = temp.replace(className, classNameStr+"Client");
}else{
//替换类名
temp = temp.replace(className, classNameStr);
}
}else if(temp.contains(reClass)){
if (reClass.contains("Factory")){
//替换返回需要实例化的类名
temp = temp.replace(reClass, classNameStr);
isClient+=1;
}else{
Class classObject=null;
try{
classObject = Class.forName(classPath.get(i));
}catch (Exception e){
compiler.compiler(classURL,packagePath+target.get(i)+".java");
classObject = Class.forName(classPath.get(i));
}
//反射获取计算类的名称
//替换返回需要实例化的类名
temp=temp.replace(reClass, classObject.getSimpleName());
}
}
//把读取的每一行添加到数组中
strBuffer.append(temp);
//换行符
strBuffer.append(System.getProperty("line.separator"));
}
bufReader.close();
PrintWriter printWriter = null;
String createClassName=null;
if (isClient>0){
//创建java对象并存放在对应的路径当中
printWriter = new PrintWriter(targetURL+classNameStr+"Client"+".java");
createClassName=targetURL+ classNameStr+"Client"+".java";
}else{
printWriter = new PrintWriter(targetURL+classNameStr+".java");
createClassName=targetURL+ classNameStr+".java";
}
//将获取数据的数组写入到创建的java对象中
printWriter.write(strBuffer.toString().toCharArray());
printWriter.flush();
printWriter.close();
compiler.compiler(classURL,createClassName);
} catch (Exception e) {
e.printStackTrace();
}
}
if (isClient==target.size()){
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入要执行的算法类");
String operation = br.readLine();
Class aClass = Class.forName("AutomaticCreateFactoryV4.OperFactory." + operation + "Client");
Object object = aClass.newInstance();
Method mainMethod = aClass.getMethod("main");
mainMethod.invoke(object);
}
}
}
其他类和没有使用热加载的一致
执行结果
总结
在程序运行的过程中把用户的需求添加到项目中,不会影响用户的时候。用户想要使用什么功能直接使用就可以了。