javaDAY5

来源:互联网 发布:杨闻萍审计 知乎 编辑:程序博客网 时间:2024/06/04 00:21

Java之控制反转和依赖注入

(转自http://www.cnblogs.com/devinzhang/p/3862942.html)

1.简介
控制反转:创建被调用者的工作不再由调用者来完成,因此称为控制反转。结合Java说,当某个Java实例需要其他Java实例时,系统自动提供一个所需要的实例,无须程序显示的new一个。所以,控制反转是,关于一个对象如何获取他所依赖的对象的引用,这个责任的反转。在有控制反转之前,是由调用者负责创建他所依赖的对象;之后,由系统负责创建。

依赖注入:纵观所有的Java应用,它们都是由一些互相协作的对象构成的。我们称这种互相协作的关系为依赖关系。假如A组件调用了B组件的方法,我们可称A组件依赖于B组件。系统创建的实例供调用者调用,也可以看作是系统将创建的实例注入调用者。

优点:因为把对象生成放在了XML里定义,所以当我们需要换一个实现子类将会变成很简单(一般这样的对象都是实现于某种接口的),只要修改XML就可以了,这样我们甚至可以实现对象的热插拨(有点象USB接口和SCSI硬盘了)。

缺点:
(1)生成一个对象的步骤变复杂了(事实上操作上还是挺简单的),对于不习惯这种方式的人,会觉得有些别扭和不直观;

(2)对象生成因为是使用反射编程,在效率上有些损耗。但相对于IoC提高的维护性和灵活性来说,这点损耗是微不足道的,除非某对象的生成对效率要求特别高;

(3)缺少IDE重构操作的支持,如果在Eclipse要对类改名,那么你还需要去XML文件里手工去改了,这似乎是所有XML方式的缺憾所在。
目的:依赖注入和控制反转,目的是为了使类与类之间解耦合,提高系统的可扩展性和可维护性,下面通过一个例子来引入这一概念。

2.案例

1)一般情况下的类耦合

Main.java

public class Main {     public static void main(String[] args) {          /******** 一般写法,Main类与Chinese类和American类之间的强耦合 ***********/          // Chinese和American,当类和方法修改时,此处的类和方法也需要修改          Chinese chinese = new Chinese();          chinese.sayHelloWorld("张三");          American american = new American();          american.sayHelloWorld("Jack");     }}

/********** 一般方法 *****************/

interface Human {     public void sayHelloWorld(String name);}class Chinese implements Human {     public void sayHelloWorld(String name) {          String helloWorld = "你好," + name;          System.out.println(helloWorld);     }}class American implements Human {     public void sayHelloWorld(String name) {          String helloWorld = "Hello," + name;          System.out.println(helloWorld);     }}

通过上面代码可以看出:Main类与Chinese类和American类之间存在着强耦合 , Chinese和American类和方法修改时,此处的类和方法也需要修改。不容易扩展和维护。

2)工厂方法来解耦合

public class Main {     public static void main(String[] args) {          /******** 工厂方法, Main类与类Chinese和American不再耦合,仅仅和其接口Human耦合 ***********/          // 修改时还需要修改在Main类中修改这些字符串          // Chinese和American,当类和方法修改时,只有方法需要修改          HumanFactory humanFactory = new HumanFactory();          Human human1 = humanFactory.getHuman("chinese");          human1.sayHelloWorld("张三");          Human human2 = humanFactory.getHuman("american");          human2.sayHelloWorld("Jack");     }}
/******************** 工厂方法 ***************************/interface Human {     public void sayHelloWorld(String name);}class HumanFactory {     public Human getHuman(String type) {          if ("chinese".equals(type)) {               return new Chinese();          } else {               return new American();          }     }}

通过上面代码可以看出:Main类与类Chinese和American不再耦合,仅仅和其接口Human耦合,修改时还需要修改在Main类中修改这些字符串,当类和方法修改时,只有方法需要修改。这一定程度上降低了Main类和Chinese、American类的耦合

3)依赖注入和控制反转

public class Main {     public static void main(String[] args) {          /******************** IOC控制反转和依赖注入 ***************************/          // 利用容器,通过xml文件直接注入属性值,在Main类中只添加需要的          // Chinese和American,当类和方法修改时,代码完全不用修改,只需要修改xml文件即可,彻底实现了解耦          BeanFactory beanFactory = new BeanFactory();          beanFactory.init("/config.xml");          UserBean userBean = (UserBean) beanFactory.getBean("userBean");          System.out.println("userName=" + userBean.getUserName());          System.out.println("password=" + userBean.getPassword());     }}
/******************** IOC控制反转和依赖注入 ***************************/// 下面是Spring的IOC实现:Bean工厂class BeanFactory {     private Map<String, Object> beanMap = new HashMap<String, Object>();     public void init(String fileName) {          try {               // 读取指定的配置文件               SAXReader reader = new SAXReader();               // System.out.println(xmlpath);               String realPathString = new File("").getCanonicalPath();               Document document = reader.read(new File(realPathString + "/src/com/devin/") + fileName);               Element root = document.getRootElement();               Element foo;               // 遍历bean               for (Iterator i = root.elementIterator("bean"); i.hasNext();) {                    foo = (Element) i.next();                    // 获取bean的属性id和class                    Attribute id = foo.attribute("id");                    Attribute cls = foo.attribute("class");                    // 利用Java反射机制,通过class的名称获取Class对象                    Class bean = Class.forName(cls.getText());                    // 获取对应class的信息                    java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean);                    // 获取其属性描述                    java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors();                    // 设置值的方法                    Method mSet = null;                    // 创建一个对象                    Object obj = bean.newInstance();                    // 遍历该bean的property属性                    for (Iterator ite = foo.elementIterator("property"); ite.hasNext();) {                         Element foo2 = (Element) ite.next();                         // 获取该property的name属性                         Attribute name = foo2.attribute("name");                         String value = null;                         // 获取该property的子元素value的值                         for (Iterator ite1 = foo2.elementIterator("value"); ite1.hasNext();) {                              Element node = (Element) ite1.next();                              value = node.getText();                              break;                         }                         for (int k = 0; k < pd.length; k++) {                              if (pd[k].getName().equalsIgnoreCase(name.getText())) {                                   mSet = pd[k].getWriteMethod();                                   mSet.invoke(obj, value);                              }                         }                    }                    // 将对象放入beanMap中,其中key为id值,value为对象                    beanMap.put(id.getText(), obj);               }          } catch (Exception e) {               System.out.println(e.toString());          }     }     // 通过bean的id获取bean的对象.     public Object getBean(String beanName) {          Object obj = beanMap.get(beanName);          return obj;     }}
UserBean.javapublic class UserBean {     private String userName;     private String password;     public String getPassword() {          return password;     }     public String getUserName() {          return userName;     }     public void setUserName(String userName) {          this.userName = userName;     }     public void setPassword(String password) {          this.password = password;     }}
config.xml<?xml version="1.0" encoding="UTF-8"?><beans>     <bean id="userBean" class="com.devin.UserBean">          <property name="userName">               <value>张三</value>          </property>          <property name="password">               <value>Jack</value>          </property>     </bean></beans>

说明:模拟了Spring中IOC的实现,虽然只是完成了Spring中依赖注入的一小部分工作,但是很好的展现了Java反射机制在Spring中的应用,能使我们能更好的从原理上了解IOC的实现。

0 0
原创粉丝点击