小言_互联网的博客

Spring 从入门到精通 (二) 反射工厂篇

333人阅读  评论(0)

关键词:Spring | 反射工厂 | 解耦

本专栏通过理论和实践相结合,系统学习框架核心思想及简单原理,原创不易,如果觉得文章对你有帮助,点赞收藏支持博主 ✨

一、知识清单

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

二、什么是硬编码?

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

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

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

三、什么是耦合?

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

四、耦合带来的问题?

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

五、什么是设计模式?

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

六、工厂设计模式

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

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

七、模拟一个简单工厂

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

Person接口

public interface Person {
   
    void Say();
}

Boy实现类

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

Girl实现类

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

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();
    }
}

可以看到没有问题

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

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

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

PersonFactory工厂类

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

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

调用测试

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();
    }
}

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

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

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

八、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;
    }
}

启动测试

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();
    }
}

结果

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

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

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

九、读取配置文件实现解耦合

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

boy=dao.Boy
girl=dao.Girl

改造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;
    }
}

 

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

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

测试类

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();
    }
}

执行后:

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

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

boy=dao.Boy
girl=dao.XiaoZhang

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

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

十、写在最后

座右铭:不要在乎别人如何看你,要在乎你自己如何看未来,看梦想,看世界…!

一起学习的可以私信博主或添加博主微信哦。

专栏:订阅专栏 ✅
关注:关注博主 🆙


转载:https://blog.csdn.net/m0_53321320/article/details/125675560
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场