再谈依赖注入(依赖注入的简单实现)

 以前说过,依赖注入就是为了解决依赖的问题的,在Spring中,原本应该本身入new的对象本身不来new了,交给bean去new。其实使用反射能够实现依赖注入。java

下面就是简单实现的方式:设计模式

使用反射能够new出新的实例,咱们能够这么作:spa

 1 public Object getInstance(String ClassName){
 2         private Object result=null;
 3         try {
 4             result=Class.forName(ClassName).newInstance();
 5         } catch (ClassNotFoundException e) {
 6             e.printStackTrace();
 7         } catch (InstantiationException e) {
 8             e.printStackTrace();
 9         } catch (IllegalAccessException e) {
10             e.printStackTrace();
11         }
12         return result;
13 }

为了保证通用性,这里使用了返回Object类型。以后能够直接在代码中调用这个方法,在反射中实现依赖注入(假设有一个User接口和他的实现类):设计

1 TestIOC testIOC=new TestIOC();
2 User user=(User)testIOC.getInstance("com.smile.UserImpl");
3 user.sayHey();

第一行为刚刚封装反射方法的类。好像仍是没有达到预知的效果,这里开始修改:code

将实现类放到外面的配置文件中,到使用的时候载注入到其中。xml

那么咱们加入了如下配置文件:对象

1 <?xml version="1.0" encoding="utf-8"?>
2 <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
3 <properties>
4     <entry key="className">com.smile.User</entry>
5 </properties>

而后在读取配置文件:blog

1 InputStream inputStream=ClassLoader.getSystemResourceAsStream("testxml.xml");
2 Properties properties=new Properties();
3 properties.loadFromXML(inputStream);
4 String ClassName=properties.getProperty("className");
5 System.out.println(ClassName);

这里好像有点似曾相识了,以前使用Spring的时候,就有相似的代码:接口

1 public void UseTest(){
2          ApplicationContext context=new ClassPathXmlApplicationContext("SpringConfig.xml");
3          Hello hello=(Hello)context.getBean("hello");
4          hello.sayHello();
5 }

读取玩配置文件还会进行下一步的操做,也会有相似的代码:utf-8

1     TestIOC testIOC=new TestIOC();
2     User user=(User)testIOC.getInstance(ClassName);
3     user.sayHey();    

是否是和Spring的代码中惊人的类似了,咱们在程序中没有本身去new对象,而是交给了咱们本身写出来的方法去new,咱们的代码会根据咱们本身写的配置文件获得配置文件的信息,而后去new配置文件中写好的对象,将依赖注入到这里,若是咱们要使用的实现类出现了变化,那么只须要修改xml配置文件中的信息就行了,大大减小了修改代码的成本。经过以上就简单的实现了依赖注入。

这种实现方式实际上使用了一种设计模式——抽象工厂。

那么抽象工厂是一种什么样的设计模式呢?提供一个建立一系列相关或相互依赖的接口对象。而无需指定具体的类。

在刚刚的代码中User就是抽象,之因此是抽象,是由于User可能会有不一样的实现,而咱们利用反射而获得的对象的方法——getInstance()就是工厂。之因此没有看到抽象工厂的影子是由于使用反射的时候不须要再代码中显示的new出对象,而类名是字符串,能够随意修改,反射取代了抽象工厂,完成了依赖注入。

若是这里使用纯粹的抽象工厂的话会出现大量的类来new咱们须要的实例,反射只须要一个方法能够new出来不少咱们须要的实例。

固然由于类过多的时候咱们也可使用简单工厂来改进抽象工厂,就是讲new的过程放到switch中new,在new的时候根据输入的字符来判断使用哪种方式,可是这里若是咱们增长一个实现类的时候,就要再次修改代码,在switch中加入case,这样仍是会很麻烦,而利用反射也改进了这里的缺点。