Spring【二】反射工厂实现解耦合

举报
周棋洛 发表于 2022/07/11 00:09:36 2022/07/11
【摘要】 主页:查看更多文章 专栏:订阅专栏 ✅ 关键:Spring 反射工厂 解耦合 IoC Spring 框架对与 Java 👨‍💻,重要性不言而喻,本专栏将系统学习框架核心思想和实现原理,...

主页:查看更多文章
专栏:订阅专栏 ✅
关键:Spring 反射工厂 解耦合 IoC

在这里插入图片描述

Spring 框架对与 Java 👨‍💻,重要性不言而喻,本专栏将系统学习框架核心思想和实现原理,理论和实践相结合,帮助刚学习框架的小伙伴摆脱困境重拾自信,原创不易,如果觉得文章对你有帮助,记得点赞收藏呀。

1. 知识清单

以下是本文将要学习的知识清单。

在这里插入图片描述

2. 什么是硬编码?

在这里插入图片描述

硬编码(Hard Code)是指在软件实现上,将输入或输出的相关参数,比如:路径、输出格式等直接以常量的方式写在源代码中,而非在程序执行期间由外界指定的设置,比如配置文件来动态改变程序状态。

硬编码是一种反模式或不完美的实现,因为想要改变输出格式就必须修改源代码,让客户改源码就好像是在开玩笑,不是吗?

但硬编码也并非完全只有缺陷,有时候制作简单的应用程序,程序可能只会执行一次或几次,并且程序需求不会变更,这时候使用硬编码缩短开发时间是不错的选择。

3. 什么是耦合?

在这里插入图片描述

程序员所说的耦合是指在程序设计中对象之间的依赖性,对象之间依赖越复杂,其耦合越高,维护成本越高,因此对象的设计应使类和构件之间的耦合最小。

4. 耦合带来的问题?

  • 无法控制各个模块对公共数据的存取,严重影响了软件模块的可靠性和适应性
  • 软件的可维护性变差,若一个模块修改了公共数据,则会影响相关模块
  • 代码的可读性变差了,不容易清楚知道哪些数据被哪些模块所共享,排错困难

5. 什么是设计模式?

在这里插入图片描述

设计模式是面向对象设计中反复出现的问题的解决方案,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。

6. 工厂设计模式

在这里插入图片描述

工厂模式是 Java 中最常用的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不再使用new关键字,而是使用一个共同的接口来创建对象。

7. 模拟一个简单工厂

先来一个简单需求,假设有一个Person接口,此接口下有一个方法Say(),此接口有两个实现类,分别是Boy和Girl,他们分别实现Say方法,使用new创建对象,测试,创建工厂类,工厂类中有两个静态方法getBoy和getGirl,它们分别返回两个对象,使用工厂类创建对象,测试

Person接口

public interface Person {
    void Say();
}

  
 
  • 1
  • 2
  • 3

Boy实现类

public class Boy implements Person {
    @Override
    public void Say() {
        System.out.println("Boy say...");
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Girl实现类

public class Girl implements Person {
    @Override
    public void Say() {
        System.out.println("Girl say...");
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

new创建对象

public class Test {
    public static void main(String[] args) {
        System.out.println("===Use New===");
        Girl girl = new Girl();
        Boy boy = new Boy();
        girl.Say();
        boy.Say();
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

可以看到没有问题

===Use New===
Girl say...
Boy say...

进程已结束,退出代码为 0

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

现在,构造工厂,很简单,两个静态方法,分别返回两个对象

PersonFactory工厂类

public class PersonFactory {
    public static Girl getGirl() {
        return new Girl();
    }

    public static Boy getBoy() {
        return new Boy();
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

调用测试

public class Test {
    public static void main(String[] args) {
        System.out.println("===Use Factory===");
        Boy boy = PersonFactory.getBoy();
        Girl girl = PersonFactory.getGirl();
        girl.Say();
        boy.Say();
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

可以看到,没有任何问题,我们已经完成了第一步改造,小伙伴们会说你的工厂类依然耦合,是的,不要着急,一步一步来

===Use Factory===
Girl say...
Boy say...

进程已结束,退出代码为 0

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

8. Java反射工厂实战

下面,我要改造一下工厂类,Java中创建对象有两种方式,一是直接new,二是使用反射机制动态创建对象,下面就使用反射机制对工厂类进行改造。

PersonFactory工厂类

改造后的反射工厂类,传入全限定名,程序根据传入全限定名结合Java反射机制创建对象

public class PersonFactory {
    public static Object getClassPathBean(String classpath) {
        Object o = null;
        try {
            /*Class.forName获取类加载器*/
            Class<?> aClass = Class.forName(classpath);
            /*使用类加载器创建对象实例*/
            o = aClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        /*返回创建的对象实例*/
        return o;
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

启动测试

public class Test {
    public static void main(String[] args) {
        System.out.println("===Use Reflection Factory===");
        /*调用工厂方法,传入类权限定名,直接返回Object
         * 因为我知道他是Boy类型的,所以可以强制转换 从而调方法*/
        Boy boy = (Boy) PersonFactory.getClassPathBean("dao.Boy");
        Girl girl = (Girl) PersonFactory.getClassPathBean("dao.Girl");
        boy.Say();
        girl.Say();
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

结果

没有任何问题,我们又离解耦进了一步,现在我想使用一个配置文件,来配置对象名和全类名,程序读取对象名的值全类名,根据全类名结合反射创建对象,这不就解耦了吗,如果类变了,我只需要该配置文件,不用去该源代码了,说干就干。

===Use Reflection Factory===
Boy say...
Girl say...

进程已结束,退出代码为 0

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

9. 读取配置文件实现解耦合

创建配置文件application.properties,这种配置文件使用键值对形式,将类名和全限定名写进去,如下:

boy=dao.Boy
girl=dao.Girl

  
 
  • 1
  • 2

改造PersonFactory ,获取输入流,加载配置文件,反射的全类名来自读取的配置文件,当我们修改配置文件时,程序就会发生变化,这就是解耦,无需去修改源代码,这里注意使用静态代码块一次读取,节省资源。

public class PersonFactory {
    private static Properties con = new Properties();

    static {
        //1. 获取输入流
        InputStream inputStream = PersonFactory.class.getResourceAsStream("/application.properties");
        //2. 加载流到con
        try {
            con.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static Object getGirl() {
        /*获取配置文件中girl的值,即全限定名*/
        String girl = con.getProperty("girl");
        Object o = null;
        try {
            /*加载类*/
            Class<?> aClass = Class.forName(girl);
            /*获取实例对象,强制转换*/
            o = aClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        /*返回对象*/
        return o;
    }

    public static Object getBoy() {
        String boy = con.getProperty("boy");
        Object o = null;
        try {
            Class<?> aClass = Class.forName(boy);
            o = aClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return o;
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

新建一个XiaoZhang类,同样实现Person接口

public class XiaoZhang implements Person{
    @Override
    public void Say() {
        System.out.println("小张是个小傻瓜。。。");
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

测试类

public class Test {
    public static void main(String[] args) {
        System.out.println("===Use Reflection Factory===");
        Person boy = (Person) PersonFactory.getBoy();
        boy.Say();
        Person girl = (Person) PersonFactory.getGirl();
        girl.Say();
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

执行后:

===Use Reflection Factory===
Boy say...
Girl say...

  
 
  • 1
  • 2
  • 3

没问题,修改配置文件girl=dao.XiaoZhang,如下:

boy=dao.Boy
girl=dao.XiaoZhang

  
 
  • 1
  • 2

无须任何修改,此时启动主程序类,首先会调用工厂类的方法,工厂类的方法去读取配置文件,因为配置文件修改了,所以根据反射创建的对象不再是Girl类型,而是XiaoZhang类型,话不多说,直接启动测试,执行结果如下:

===Use Reflection Factory===
Boy say...
小张是个小傻瓜。。。

  
 
  • 1
  • 2
  • 3

是不是醍醐灌顶的感觉,嘿嘿,接下来就是仔细品,直到理解了,这就是全部内容了,我们下期再见。

在这里插入图片描述

文章来源: blog.csdn.net,作者:王子周棋洛,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/m0_53321320/article/details/125675560

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。