`

关于工厂模式和spring的IOC

阅读更多

原文转之:

http://gocom.primeton.com/modules/gSpace/modules/techresource/article608.htm?PHPSESSID=df81a3fde2d88ab19b2a3588347d1d6d

http://gocom.primeton.com/modules/gSpace/pick1061.htm?PHPSESSID=df81a3fde2d88ab19b2a3588347d1d6d

 

Spring的模块化是很强的,各个功能模块都是独立的,我们可以选择的使用。这一章先从Spring的IoC开始。所谓IoC就是一个用XML来定义生成对象的模式,我们看看如果来使用的。

   数据模型

   1、如下图所示有三个类,Human(人类)是接口,Chinese(中国人)是一个子类,American(美国人)是另外一个子类。

源代码如下:

java 代码
  1. package cn.com.chengang.spring;   
  2. public interface Human {   
  3. void eat();   
  4. void walk();   
  5. }   
  6.   
  7. package cn.com.chengang.spring;   
  8. public class Chinese implements Human {   
  9. /* (非 Javadoc)  
  10. * @see cn.com.chengang.spring.Human#eat()  
  11. */  
  12. public void eat() {   
  13. System.out.println("中国人对吃很有一套");   
  14. }   
  15.   
  16. /* (非 Javadoc)  
  17. * @see cn.com.chengang.spring.Human#walk()  
  18. */  
  19. public void walk() {   
  20. System.out.println("中国人行如飞");   
  21. }   
  22. }   
  23.   
  24. package cn.com.chengang.spring;   
  25. public class American implements Human {   
  26. /* (非 Javadoc)  
  27. * @see cn.com.chengang.spring.Human#eat()  
  28. */  
  29. public void eat() {   
  30. System.out.println("美国人主要以面包为主");   
  31. }   
  32.   
  33. /* (非 Javadoc)  
  34. * @see cn.com.chengang.spring.Human#walk()  
  35. */  
  36. public void walk() {   
  37. System.out.println("美国人以车代步,有四肢退化的趋势");   
  38. }   
  39. }  

 

2、对以上对象采用工厂模式的用法如下

   创建一个工厂类Factory,如下。这个工厂类里定义了两个字符串常量,所标识不同的人种。getHuman方法根据传入参数的字串,来判断要生成什么样的人种。

java 代码
  1. package cn.com.chengang.spring;   
  2. public class Factory {   
  3. public final static String CHINESE = "Chinese";   
  4. public final static String AMERICAN = "American";   
  5.   
  6. public Human getHuman(String ethnic) {   
  7. if (ethnic.equals(CHINESE))   
  8. return new Chinese();   
  9. else if (ethnic.equals(AMERICAN))   
  10. return new American();   
  11. else  
  12. throw new IllegalArgumentException("参数(人种)错误");   
  13. }   
  14. }  

 

下面是一个测试的程序,使用工厂方法来得到了不同的“人种对象”,并执行相应的方法。

java 代码
  1. package cn.com.chengang.spring;   
  2. public class ClientTest {   
  3. public static void main(String[] args) {   
  4. Human human = null;   
  5. human = new Factory().getHuman(Factory.CHINESE);   
  6. human.eat();   
  7. human.walk();   
  8. human = new Factory().getHuman(Factory.AMERICAN);   
  9. human.eat();   
  10. human.walk();   
  11. }   
  12. }  

 

 3、采用Spring的IoC的用法如下:

   在项目根目录下创建一个bean.xml文件

xml 代码
  1. <?xml version="1.0" encoding="UTF-8"?>   
  2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">   
  3. <beans>   
  4. <bean id="Chinese" class="cn.com.chengang.spring.Chinese"/>   
  5. <bean id="American" class="cn.com.chengang.spring.American"/>   
  6. </beans>  

修改ClientTest程序如下:

java 代码
  1. package cn.com.chengang.spring;   
  2. import org.springframework.context.ApplicationContext;   
  3. import org.springframework.context.support.FileSystemXmlApplicationContext;   
  4. public class ClientTest {   
  5. public final static String CHINESE = "Chinese";   
  6. public final static String AMERICAN = "American";   
  7.   
  8. public static void main(String[] args) {   
  9. // Human human = null;   
  10. // human = new Factory().getHuman(Factory.CHINESE);   
  11. // human.eat();   
  12. // human.walk();   
  13. // human = new Factory().getHuman(Factory.AMERICAN);   
  14. // human.eat();   
  15. // human.walk();   
  16.   
  17. ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");   
  18. Human human = null;   
  19. human = (Human) ctx.getBean(CHINESE);   
  20. human.eat();   
  21. human.walk();   
  22. human = (Human) ctx.getBean(AMERICAN);   
  23. human.eat();   
  24. human.walk();   
  25. }   
  26. }  

 从这个程序可以看到,ctx就相当于原来的Factory工厂,原来的Factory就可以删除掉了。然后又把Factory里的两个常量移到了ClientTest类里,整个程序结构基本一样。

   再回头看原来的bean.xml文件的这一句:

<bean id="Chinese" class="cn.com.chengang.spring.Chinese"/>

   id就是ctx.getBean的参数值,一个字符串。class就是一个类(包名+类名)。然后在ClientTest类里获得Chinese对象就是这么一句

human = (Human) ctx.getBean(CHINESE);

   因为getBean方法返回的是Object类型,所以前面要加一个类型转换。

   总结

   (1)也许有人说,IoC和工厂模式不是一样的作用吗,用IoC好象还麻烦一点。

   举个例子,如果用户需求发生变化,要把Chinese类修改一下。那么前一种工厂模式,就要更改Factory类的方法,并且重新编译布署。而IoC只需要将class属性改变一下,并且由于IoC利用了Java反射机制,这些对象是动态生成的,这时我们就可以热插拨Chinese对象(不必把原程序停止下来重新编译布署)

   (2)也许有人说,即然IoC这么好,那么我把系统所有对象都用IoC方式来生成。

   注意,IoC的灵活性是有代价的:设置步骤麻烦、生成对象的方式不直观、反射比正常生成对象在效率上慢一点。因此使用IoC要看有没有必要,我认为比较通用的判断方式是:用到工厂模式的地方都可以考虑用IoC模式。

   (3)在上面的IoC的方式里,还有一些可以变化的地方。比如,bean.xml不一定要放在项目录下,也可以放在其他地方,比如cn.com.chengang.spring包里。不过在使用时也要变化一下,如下所示:

new FileSystemXmlApplicationContext("src/cn/com/chengang/spring/bean.xml");

   另外,bean.xml也可以改成其他名字。这样我们在系统中就可以分门别类的设置不同的bean.xml。

   (4)关于IoC的低侵入性。

   什么是低侵入性?如果你用过Struts或EJB就会发现,要继承一些接口或类,才能利用它们的框架开发。这样,系统就被绑定在Struts、EJB上了,对系统的可移植性产生不利的影响。如果代码中很少涉及某一个框架的代码,那么这个框架就可以称做是一个低侵入性的框架。

   Spring的侵入性很低,Humen.java、Chinese.java等几个类都不必继承什么接口或类。但在ClientTest里还是有一些Spring的影子:FileSystemXmlApplicationContext类和ctx.getBean方式等。
现在,低侵入性似乎也成了判定一个框架的实现技术好坏的标准之一。

   (5)关于bean.xml的用法

   bean.xml的用法还有很多,其中内容是相当丰富的。假设Chinese类里有一个humenName属性(姓名),那么原的bean.xml修改如下。此后生成Chinese对象时,“陈刚”这个值将自动设置到Chinese类的humenName属性中。而且由于singleton为true这时生成Chinese对象将采用单例模式,系统仅存在一个Chinese对象实例。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="Chinese" class="cn.com.chengang.spring.Chinese" singleton="true">
<property name="humenName">
<value>陈刚</value>
</property>
</bean>
<bean id="American" class="cn.com.chengang.spring.American"/>
</beans>

   关于bean.xml的其它用法,不再详细介绍了,大家自己拿Spring的文档一看就明白了。

 Spring能有效地组织J2EE应用各层的对象。不管是控制层的Action对象,还是业务层的Service对象,还是持久层的DAO对象,都可在Spring的管理下有机地协调、运行。Spring将各层的对象以松耦合的方式组织在一起,Action对象无须关心Service对象的具体实现,Service对象无须关心持久层对象的具体实现,各层对象的调用完全面向接口。当系统需要重构时,代码的改写量将大大减少。

  上面所说的一切都得宜于Spring的核心机制,依赖注入。依赖注入让bean与bean之间以配置文件组织在一起,而不是以硬编码的方式耦合在一起。理解依赖注入

  依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。

  不管是依赖注入,还是控制反转,都说明Spring采用动态、灵活的方式来管理各种对象。对象与对象之间的具体实现互相透明。在理解依赖注入之前,看如下这个问题在各种社会形态里如何解决:一个人(Java实例,调用者)需要一把斧子(Java实例,被调用者)。

  (1)原始社会里,几乎没有社会分工。需要斧子的人(调用者)只能自己去磨一把斧子(被调用者)。对应的情形为:Java程序里的调用者自己创建被调用者。

  (2)进入工业社会,工厂出现。斧子不再由普通人完成,而在工厂里被生产出来,此时需要斧子的人(调用者)找到工厂,购买斧子,无须关心斧子的制造过程。对应Java程序的简单工厂的设计模式。

  (3)进入“按需分配”社会,需要斧子的人不需要找到工厂,坐在家里发出一个简单指令:需要斧子。斧子就自然出现在他面前。对应Spring的依赖注入。

  第一种情况下,Java实例的调用者创建被调用的Java实例,必然要求被调用的Java类出现在调用者的代码里。无法实现二者之间的松耦合。

  第二种情况下,调用者无须关心被调用者具体实现过程,只需要找到符合某种标准(接口)的实例,即可使用。此时调用的代码面向接口编程,可以让调用者和被调用者解耦,这也是工厂模式大量使用的原因。但调用者需要自己定位工厂,调用者与特定工厂耦合在一起。

  第三种情况下,调用者无须自己定位工厂,程序运行到需要被调用者时,系统自动提供被调用者实例。事实上,调用者和被调用者都处于Spring的管理下,二者之间的依赖关系由Spring提供。

  所谓依赖注入,是指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。Spring的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对POJO之间依赖关系的管理。依赖注入通常有两种:

  ·设值注入。

  ·构造注入。
.......

 

分享到:
评论
2 楼 小尜 2015-11-11  
写的很详细,也很简单,一看就懂。多谢啦。
1 楼 huajz 2007-06-26  
非顶不可!!!

相关推荐

    工厂模式的测试并有spring ioc的简单实现

    在Spring中,工厂模式可以与IoC容器结合使用,例如在【springFactory】和【springFactoryJDOM】的示例中,我们可能会看到如何使用Spring的Bean工厂来创建和管理对象。Spring提供了XML配置和注解两种方式来声明和管理...

    spring ioc

    IOC 是一种设计模式,它将对象的创建和管理权反转,由框架负责管理对象的生命周期,而不是由对象自身管理。这样,开发者可以更专注于业务逻辑,而无需关心对象的实例化、配置和组装。在 Spring 中,这种机制通过容器...

    Spring IoC依赖包

    1. `spring-beans.jar`: 这个包包含了Spring框架的基本组件,如Bean工厂,它是IoC容器的基础,负责读取配置元数据(XML或Java注解),并根据这些信息创建和管理Bean。 2. `spring-context.jar`: 这个包扩展了`...

    Java Spring代理模式AOP-IOC分析

    Java Spring代理模式AOP-IOC分析 一、代理模式概述 在软件设计中,代理模式是一种常用的设计模式。...本文对Java Spring代理模式AOP-IOC进行了分析和讨论,并提供了一个示例项目来演示如何使用Spring实现AOP和IOC。

    以注解方式模拟Spring IoC AOP

    在Spring框架中,依赖注入(Inversion of Control, IoC)和面向切面编程(Aspect Oriented Programming, AOP)是两大核心特性。本篇将深入探讨如何通过注解方式来模拟Spring的这两种机制,帮助你理解其底层原理。 #...

    Java反射_Spring IOC

    3. Spring IOC基础:讲解Spring框架的核心概念,如Bean工厂、ApplicationContext和依赖注入。 4. Spring的XML配置与注解配置:如何在XML文件中声明Bean和依赖,以及使用注解实现相同功能。 5. Spring的AOP:如何通过...

    springioc的详细讲解

    综上所述,Spring的IOC容器是通过控制反转和依赖注入实现的一种高级组件管理机制,它极大地简化了Java应用的复杂性,促进了松耦合和可测试性的提升。理解并熟练运用Spring IOC容器是掌握Spring框架的关键。通过阅读...

    Spring IOC源码解读

    Spring IOC,即Inversion of Control(控制反转),是Spring框架的核心特性之一,它负责管理和装配应用程序中的对象。在传统的编程模式中,对象通常自行创建和管理它们所依赖的其他对象,这导致了代码间的高耦合。而...

    手写spring ioc(三) 资源org.zip

    总的来说,手写Spring IOC是一个深入理解和实践IoC设计模式的好方法,它能帮助开发者更深入地了解Spring框架的工作原理,提高对依赖注入和对象管理的理解。通过这个过程,我们可以更好地掌握如何在实际项目中应用...

    SpringIOC和AOP实现机制模拟

    首先,Spring的控制反转(IOC)是一种设计模式,它将对象的创建和管理权从代码中移出,交由Spring容器负责。这样可以降低组件之间的耦合,提高代码的可测试性和可维护性。在Spring中,IOC主要通过以下几种方式实现:...

    JavaEE spring IoC入门案例

    JavaEE Spring 框架是企业级应用开发的首选之一,尤其在控制反转(Inversion of Control, 简称IoC)和依赖注入(Dependency Injection, DI)方面表现出色。IoC是一种设计模式,它将对象的创建和管理从应用程序的业务...

    Spring ioc源码解读

    通过对Spring IoC容器的理解和源码分析,我们可以深入了解到Spring框架是如何管理和控制应用对象的生命周期及依赖关系的。在实际开发中,了解Spring IoC容器的工作原理有助于更好地利用Spring框架,提高开发效率和...

    spring IOC

    Spring采用工厂模式创建Bean,同时使用反射和CGLIB动态代理技术来处理对象的实例化和依赖注入。当我们声明一个Bean时,Spring会通过反射找到对应的类并实例化,如果需要,还会创建代理对象以便于AOP(面向切面编程)...

    Java-Spring-SpringIoC容器-SpringIoC的学习

    Spring IoC容器通过读取XML配置文件或使用注解来管理对象的生命周期和依赖关系。它首先解析配置元数据,然后根据这些信息创建和组装对象。在XML配置中,`<bean>`标签用于定义一个Java对象,`class`属性指明该对象的...

    一个简单的模仿spring的ioc实现

    总之,这个项目是学习和理解Spring Ioc的一个很好的起点,它可以帮助我们剥离Spring的复杂性,专注于IoC的核心原理。通过实践,我们可以更好地掌握这一关键的编程模式,并将其应用到实际的软件开发中。

    springioc的搭建和配置

    - **BeanFactory**: 是工厂模式的一种实现,负责创建和管理 bean。它提供了如下几个核心方法: - `containsBean(String name)`: 判断容器中是否存在某个名称的 bean。 - `getBean(String name)`: 获取指定名称的 ...

    工厂模式的IoC应用

    工厂模式的IoC应用,特别是在Spring框架中,是一个强大的工具,可以显著提高代码的可维护性和可测试性。`BeanFactory`作为Spring的核心组件,负责bean的创建、依赖注入、生命周期管理和作用域控制,使得开发人员能够...

    springIOC小程序

    在传统的软件开发中,对象的创建和依赖关系通常由对象自身来处理,而在Spring IOC模式下,这些控制权被"反转"给了一个叫做IoC容器的组件。这个容器负责管理对象的生命周期和对象之间的依赖关系。 在"springIOC小...

    手写一个SpringIoc容器

    本项目"手写一个SpringIoc容器"旨在模仿Spring的IOC(Inversion of Control,控制反转)功能,帮助开发者深入理解Spring的工作原理,提升对依赖注入(Dependency Injection)模式的认识。 在实现自定义的Spring IOC...

Global site tag (gtag.js) - Google Analytics