设计模式-工厂方法模式

简介: 设计模式-工厂方法模式

文章目录

发展:

简单实现:

命名不规范:

可读性差

可维护性差

可扩展性差

团队合作问题

除数不能为0问题:

开闭原则问题:

想象力创造力:

首先是发现力:

接下来是想象力:

总结


大话设计模式这本书反反复复学过好多遍了,每一次学都会有不同的认识,接下来谈谈我最近学习工厂的一次感受;

发展:

一个计算器的例子从不使用工厂到分离出前端、后端,到使用简单工厂再到使用工厂方法,每一步的变化都是巨大的;


简单实现:

简单实现的版本中存在着大量的问题,命名不规范啊,除数不能为0,前后端没有进行分离导致无法复用后端;违反开闭原则,新增运算的业务需要修改代码才可以;


命名不规范:

我们写代码是为了给别人看的,不是能运行就可以,一个好的程序员写出来的代码要能让被人看一眼就能知道你这里写的是什么,如果我们随便对变量进行命名,任谁来也不能马上知道你写的是什么意思,所以命名不规范就导致了你写的这段程序一个人开发的,维护的时候,需要一百个人来维护,浪费人力、物力、财力,千万不要小看命名的问题;


可读性差

不规范的命名会使代码难以理解和阅读,增加了其他开发人员理解代码的难度。当代码命名不清晰时,读者需要花费更多的时间和精力来推断变量、函数或类的用途和含义。


可维护性差

命名不规范会给代码维护带来困难。当代码需要修改或调试时,不规范的命名可能会让开发人员困惑,导致错误的修改或调试行为。同时,不规范的命名还会影响代码的重构,增加了重构的难度和风险。


可扩展性差

命名不规范会限制代码的可扩展性。当新功能需要添加或现有功能需要扩展时,不规范的命名可能会导致冲突、歧义或混乱,使得代码的扩展变得困难。良好的命名规范可以提高代码的可扩展性,使得新功能的添加和现有功能的扩展更加容易和可靠。


团队合作问题

不规范的命名会给团队协作带来问题。在团队开发中,成员之间需要相互理解和协作。如果命名不规范,代码的含义和用途可能会被误解,导致沟通困难和合作效率降低。


除数不能为0问题:

这里问题就更严重了,只有没有把用户当猪的开发者才能写出这种代码,没有把用户当猪,总想着用户能知道除法运算中除数不能为0,把这种生死权交在了用户的手中,只有用户在使用软件的过程中按照正确的方式输入才可以使用,但是如果用户没有按照正确的方式输入的,那你的系统岂不是直接挂了,在用户看来就是这什么软件啊,我输入个0都不行,导致用户骂你,骂你的软件,用户是你最大的收益,用户不用了,你也就失业了。


开闭原则问题:

我们说写代码不按照6大设计原则写的写出来的代码都是垃圾,我们写代码是为了让别人复用的;写了一段程序,别人想用的话你这还得改来改去,想想,这样别人会用吗?


想象力创造力:

创造力是基于想象力的,没有想象力,创造力根本无法实施,航天工程固然伟大,相比来说嫦娥奔月这个想法更加伟大,没有嫦娥奔月的想象力是不可能造出航天飞行器的;


cdeee3c6a63746bf9c1b686b479d5579.png


这是一个工厂方法模式的类图, 接下来代码实现:

public abstract class Operation {
    private double numberA = 0;
    private double numberB = 0;
    public abstract double GetResult() throws Exception;
    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 interface OperationFactory {
    Operation createOperate();
}
public class OperationAdd extends Operation {
    @Override
    public double GetResult() {
        return getNumberA()+getNumberB();
    }
}
public class OperationFactoryAdd implements OperationFactory {
    @Override
    public Operation createOperate() {
        return new OperationAdd();
    }
}
public static void main(String[] args) throws Exception {
        OperationFactory operationFactory = new OperationFactoryAdd();
        Operation operate = operationFactory.createOperate();
        operate.setNumberA(11);
        operate.setNumberB(22);
        double result = operate.GetResult();
        System.out.println(result);
    }


首先是发现力:

以此我们发现运算类工厂中的代码基本都是一致的,只有涉及到创建出不用运算类对象的名字部分是不一样的;


接下来是想象力:

我们就想,既然代码基本都是一致的,我可不可以写一个模板,让程序来帮我写工厂的这段代码,这样每当我有一个写的运算类添加的时候,这样重复性的东西就不用手写了呀;


有了这样的想象力之后是创造力:

工厂模板,用于让程序帮我们实现自动写代码

public class FactoryTemplate {
    public String createFactory(String operationName) throws Exception{
        String srcFactoryCode = "package com.mengjie.saomiao.operationFactory;\n" +
                "import com.mengjie.saomiao.Operation;\n" +
                "import com.mengjie.saomiao.OperationFactory;\n" +
                "import com.mengjie.saomiao.operation."+operationName+";\n" +
                "public class" + " " + operationName+"Factory" + " " + "implements OperationFactory {\n" +
                "    @Override\n" +
                "    public Operation createOperate() {\n" +
                "        return new" + " " + operationName + "();\n" +
                "    }\n" +
                "}";
        String srcFilePath = "E:\\study\\Practice\\auto\\src\\main\\java\\com\\mengjie\\saomiao\\operationFactory\\" + operationName+"Factory" + ".java";
        FileWriter fileWriter = null;
        File file = new File(srcFilePath);
        if (!file.exists()) {
            file.createNewFile();
        }
        fileWriter = new FileWriter(srcFilePath);
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
        bufferedWriter.write(srcFactoryCode);
        bufferedWriter.close();
        return srcFilePath;
    }
}

编译工具类,用于我们让程序帮我们写出来代码时候,新增的工厂类没有编译成字节码文件的话我们的程序是没有办法帮我们执行的;

public class Compiler {
    private String classPath;
    private String filePath;
    public Compiler(String classPath, String filePath) {
        this.classPath = classPath;
        this.filePath = filePath;
    }
    public void compiler() {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        int status = compiler.run(null, null, null, "-d",classPath,filePath);
        if(status!=0){
            System.out.println("没有编译成功!");
        }
    }
}

自动扫描,每次都获取一个文件夹中的所有的运算类,将类名最终截取出来,传入创建工程类的模板中让程序来帮我们写代码;

public class Scan {
    public void scan() throws Exception {
        String packagePath = "E:\\study\\Practice\\auto\\src\\main\\java\\com\\mengjie\\saomiao\\operation";
        File file = new File(packagePath);
        if (file.isDirectory()){
            File[] files = file.listFiles();
            Map<Object, Method> map = new HashMap<>();
            for (File f : files){
                String fileName = f.getAbsolutePath();
                if (fileName.endsWith(".java")){
                    String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".java"));
                    String replacedName = className.replace("com\\mengjie\\saomiao\\operation\\", "");
                    FactoryTemplate factoryTemplate = new FactoryTemplate();
                    String factoryClassPath = factoryTemplate.createFactory(replacedName);
                    //调用一个编译源码的方法,将创建出的.java文件编译成.class文件
                    Compiler compilerOperation = new Compiler(System.getProperty("user.dir")+"\\auto\\target\\classes",fileName);
                    compilerOperation.compiler();
                    //调用一个编译源码的方法,将创建出的.java文件编译成.class文件
                    Compiler compilerFactory = new Compiler(System.getProperty("user.dir")+"\\auto\\target\\classes",factoryClassPath);
                    compilerFactory.compiler();
                    ClientTemplate clientTemplate = new ClientTemplate();
                    String clientClassPath = clientTemplate.createClient(replacedName);
                    //调用一个编译源码的方法,将创建出的.java文件编译成.class文件
                    Compiler compilerClient = new Compiler(System.getProperty("user.dir")+"\\auto\\target\\classes",clientClassPath);
                    compilerClient.compiler();
                    String compileClassName = "com.mengjie.saomiao.client."+replacedName+"Client";
                    Class<?> classLoaderClass = Class.forName(compileClassName);
                    Object instance = classLoaderClass.getConstructor().newInstance();
                    Method method = classLoaderClass.getMethod("main",String[].class);
                    map.put(instance,method);
                    method.invoke(null,  new String[]{""});
                }
            }
        }
    }
}


总结

工厂方法模式提供了一种将对象的创建与使用分离的方式,通过定义一个创建对象的工厂接口,让子类决定实例化哪个具体类。工厂方法模式可以在不知道具体对象类型的情况下创建对象,使代码更加灵活和可扩展。

目录
相关文章
|
1月前
|
设计模式 SQL 算法
设计模式了解哪些,模版模式
设计模式了解哪些,模版模式
22 0
|
1月前
|
设计模式 开发者
探讨常见设计模式 - 工厂方法模式的最佳实践和潜在的实施问题
【4月更文挑战第7天】工厂方法模式是创建型设计模式,提供了一种在不指定具体类情况下创建对象的方式。它定义创建对象的接口,允许子类决定实例化哪个类,从而解耦对象的创建和使用。最佳实践包括明确接口、封装创建逻辑、提供扩展点和避免过度使用。然而,过度工程、违反开闭原则、性能影响和依赖管理是可能的问题。通过权衡利弊并遵循最佳实践,工厂方法模式能在适当场景下提升代码灵活性和可扩展性。
|
1月前
|
设计模式 Java 数据库
小谈设计模式(2)—简单工厂模式
小谈设计模式(2)—简单工厂模式
|
1月前
|
设计模式 Java PHP
php设计模式--简单工厂模式(一)
php设计模式--简单工厂模式(一)
15 0
|
1天前
|
设计模式 JavaScript 前端开发
js设计模式-观察者模式与发布/订阅模式
观察者模式和发布/订阅模式是JavaScript中的两种设计模式,用于处理对象间的通信和事件处理。观察者模式中,一个主题对象状态改变会通知所有观察者。实现包括定义主题和观察者对象,以及在主题中添加、删除和通知观察者的功能。发布/订阅模式则引入事件管理器,允许发布者发布事件,订阅者通过订阅接收通知。
|
12天前
|
设计模式 前端开发 Java
19:Web开发模式与MVC设计模式-Java Web
19:Web开发模式与MVC设计模式-Java Web
22 4
|
17天前
|
设计模式 消息中间件 Java
Java 设计模式:探索发布-订阅模式的原理与应用
【4月更文挑战第27天】发布-订阅模式是一种消息传递范式,被广泛用于构建松散耦合的系统。在 Java 中,这种模式允许多个对象监听和响应感兴趣的事件。
37 2
|
20天前
|
设计模式 存储 JavaScript
[设计模式Java实现附plantuml源码~创建型] 多态工厂的实现——工厂方法模式
[设计模式Java实现附plantuml源码~创建型] 多态工厂的实现——工厂方法模式
|
20天前
|
设计模式 Java Go
[设计模式Java实现附plantuml源码~创建型] 集中式工厂的实现~简单工厂模式
[设计模式Java实现附plantuml源码~创建型] 集中式工厂的实现~简单工厂模式
|
20天前
|
设计模式 测试技术 Go
[设计模式 Go实现] 创建型~工厂方法模式
[设计模式 Go实现] 创建型~工厂方法模式