关于工厂模式和 spring 的 IOC
关于工厂模式和 spring 的 IOC
关于工厂模式和 spring 的 IOC_Java_xinkong1010 的专栏 - CSDN 博客
原文转之:
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 代码 package cn.com.chengang.spring;
public interface Human {
void eat();
void walk();
}
package cn.com.chengang.spring;
public class Chinese implements Human {
/* (非 Javadoc)
* @see cn.com.chengang.spring.Human#eat()
/
public void eat() {
System.out.println("中国人对吃很有一套");
}
/ (非 Javadoc)
* @see cn.com.chengang.spring.Human#walk()
/
public void walk() {
System.out.println("中国人行如飞");
}
}
package cn.com.chengang.spring;
public class American implements Human {
/ (非 Javadoc)
* @see cn.com.chengang.spring.Human#eat()
/
public void eat() {
System.out.println("美国人主要以面包为主");
}
/ (非 Javadoc)
* @see cn.com.chengang.spring.Human#walk()
*/
public void walk() {
System.out.println("美国人以车代步,有四肢退化的趋势");
}
}
2、对以上对象采用工厂模式的用法如下
创建一个工厂类 Factory,如下。这个工厂类里定义了两个字符串常量,所标识不同的人种。getHuman 方法根据传入参数的字串,来判断要生成什么样的人种。
java 代码 package cn.com.chengang.spring;
public class Factory {
public final static String CHINESE = "Chinese";
public final static String AMERICAN = "American";
public Human getHuman(String ethnic) {
if (ethnic.equals(CHINESE))
return new Chinese();
else if (ethnic.equals(AMERICAN))
return new American();
else
throw new IllegalArgumentException("参数 (人种) 错误");
}
}
下面是一个测试的程序,使用工厂方法来得到了不同的 “人种对象”,并执行相应的方法。
java 代码 package cn.com.chengang.spring;
public class ClientTest {
public static void main(String[] args) {
Human human = null;
human = new Factory().getHuman(Factory.CHINESE);
human.eat();
human.walk();
human = new Factory().getHuman(Factory.AMERICAN);
human.eat();
human.walk();
}
}
3、采用 Spring 的 IoC 的用法如下:
在项目根目录下创建一个 bean.xml 文件
xml 代码<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean/>
<bean/>
</beans>
修改 ClientTest 程序如下:
java 代码 package cn.com.chengang.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class ClientTest {
public final static String CHINESE = "Chinese";
public final static String AMERICAN = "American";
public static void main(String[] args) {
// Human human = null;
// human = new Factory().getHuman(Factory.CHINESE);
// human.eat();
// human.walk();
// human = new Factory().getHuman(Factory.AMERICAN);
// human.eat();
// human.walk();
ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
Human human = null;
human = (Human) ctx.getBean(CHINESE);
human.eat();
human.walk();
human = (Human) ctx.getBean(AMERICAN);
human.eat();
human.walk();
}
}
从这个程序可以看到,ctx 就相当于原来的 Factory 工厂,原来的 Factory 就可以删除掉了。然后又把 Factory 里的两个常量移到了 ClientTest 类里,整个程序结构基本一样。
再回头看原来的 bean.xml 文件的这一句:
<bean/>
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 singleton="true">
<property name="humenName">
<value>陈刚</value>
</property>
</bean>
<bean/>
</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 之间依赖关系的管理。依赖注入通常有两种:
· 设值注入。
· 构造注入。
全文完
本文由 简悦 SimpRead 优化,用以提升阅读体验
使用了 全新的简悦词法分析引擎 beta,点击查看详细说明

浙公网安备 33010602011771号