从一个例子开始讲起:
首先我们建立一个Chinese.Java类,该类的sayHelloWorld(String name)方法,用中文对名为name的人问好,其内容如下:
- public class Chinese {
- /**-- 用中文对某人问好. --*/
- publicvoid sayHelloWorld(String name) {
- String helloWorld = "你好," + name;
- System.out.println(helloWorld);
- }
- }
下面我们接着建立一个American.java类,该类的sayHelloWorld(String name)方法,用英文对名为name的人问好,其内容如下:下面我们接着建立一个American.java类,该类的sayHelloWorld(String name)方法,用英文对名为name的人问好,其内容如下:
- publicclass American {
- /*-- 用英文对某人问好 --*/
- publicvoid sayHelloWorld(String name) {
- String helloWorld = "Hello," + name;
- System.out.println(helloWorld);
- }
- }
最后我们编写一个测试类对这两个类的sayHelloWorld(String name)方法进行测试,下面是该类的内容:
- publicclass HelloWorldTest {
- /*-- 测试Chinese和American的sayHelloWorld()方法 --*/
- publicstaticvoid main(String[] args) {
- Chinese chinese = new Chinese();
- chinese.sayHelloWorld("极度暴走");
- American american = new American();
- american.sayHelloWorld("jidubaozou");
- }
- }
现实生活中我们总是把同一类产品放在一个工厂中生产,消费者只需要告诉工厂自己需要这一类产品中的哪一种产品,工厂就能够生产出对应的产品,从而完成交易。
这里我们把上面例子中的HelloWorldTest类想象为消费者,而Chinese和American类想象为产品,根据上面的例子,我们可以看到每当HelloWorldTest这个消费者需要一个产品时都要去自己去生产(new),这样消费者就不得不去了解各个产品的内部结构及生产过程。显然对于消费者来说这样是很麻烦的。
而在程序设计领域中这个问题就叫做强耦合问题,HelloWorldTest类与Chinese和American这两个类都存在强耦合关系。设想一下,如果程序中的很多类都需要用到Chinese和American类这两个类,那么每个类就必须和这两个类强耦合,而且现实的项目中类似于Chinese这种类往往不仅两个,这样会使得整个程序的耦合度很高,增大程序的复杂度。这时我们就想到,能否也使用一个工厂来生产这些类,这样如果某个类需要用到工厂中的哪个类,就只要通过和工厂生产就行了,从而降低了整个程序的耦合度。
下面看看工厂模式是如何实现的:
首先建立接口类Human.java,其内容如下:
- public interface Human {
- /** *//**
- * 对某人问好.
- * @param name 姓名
- */
- public void sayHelloWorld(String name);
- }
并将American.java类和Chinese.java类改为实现该接口,即类头分别改成:public class American implements Human和public class Chinese implements Human。
接着编写HumanFactory.java工厂类,其内容为:
- public class HumanFactory {
- /** *//**
- * 通过类型字段获取人的相应实例
- * @param type 类型
- * @return 返回相应实例
- */
- public Human getHuman(String type) {
- if ("chinese".equals(type)) {
- return new Chinese();
- } else {
- return new American();
- }
- }
- }
最后我们还需要修改测试类HelloWorld.java类,修改后的内容如下:
- public class HelloWorldTest {
- /** *//**
- * 测试sayHelloWorld()方法.
- * @param args
- */
- public static void main(String[] args) {
- HumanFactory factory = new HumanFactory();
- Human human1 = factory.getHuman("chinese");
- human1.sayHelloWorld("极度暴走");
- Human human2 = factory.getHuman("american");
- human2.sayHelloWorld("jidubaozou");
- }
- }
通过上面的例子可以看到,使用工厂模式实现的方式, HelloWorldTest 不再与Chinese类和American类耦合,而只是和他们共同的接口耦合,从而很大程度的降低的程序的耦合性。到这里或许很多人会有一点疑虑,使用工厂模式的HelloWorldTest 类也是需要耦合两个类(即HumanFactory 类和Human 接口)那么为什么能说降低耦合度呢,这就要是何时要使用工厂模式的问题了。假如类似于我们这个例子,HumanFactory 这个工厂只生产两个类,那的确没有什么必要使用工厂模式,但是现实的项目中往往有更多和Chinese类类似的类,比如English,Japanese,这时候就能体现出工厂模式的优势了
(二)spring IOC的原理
首先我们来讲下为什么要引入IOC:
假设上面举例的那个程序已经部署到服务器中,并已经上线运行,这时项目来了这样一个新需求:增加一个Japanese类,并且在HelloWorldTest 类中调用Japanese的sayHelloWorld方法。在没有引入IOC之前,很显然我们为了这个新需求,必须把项目停止下来,然后从新编译HumanFactory 和HelloWorldTest这两个类,最后再重新上线运行。
而使用IOC,则能够在不重新编译部署的情况下实现上面的新需求!
那么我们来看一下IOC是去怎么实现这个新需求的:
首先我们在com.human包内创建一个Japanese类:
- public class Japanese implements Human{
- private String name;
- private String age;
- public void sayHelloWorld(String string){
- System.out.println("你好,"+string);
- }
- public String getAge() {
- return age;
- }
- public void setAge(String age) {
- this.age = age;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
然后对HelloWorldTest 类做如下修改
- public class HelloWorldTest {
- public static void main(String[] args) {
- ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
- BeanFactory beanFactory=ctx.getBeanFactory();
- Human human=beanFactory.getBean("human");
- human.sayHelloWorld("极度暴走");
- }
- }
然后我们在beans.xml中做如下配置:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans>
- <bean id="human" class="com.human.Japanese">
- <property name="name">
- <value>漩涡鸣人</value>
- </property>
- <property name="password">
- <value>22</value>
- </property>
- <pre class="html" name="code"></bean>
- </beans>
总结:从上面的代码可以看出Spring的bean工厂主要实现了以下几个步骤
1.解析配置文件(bean.xml)
2.使用反射机制动态加载每个class节点中配置的类
3.为每个class节点中配置的类实例化一个对象
4.使用反射机制调用各个对象的seter方法,将配置文件中的属性值设置进对应的对象
5.将这些对象放在一个存储空间(beanMap)中</p>
6.使用getBean方法从存储空间(beanMap)中取出指定的JavaBean
PS:IOC的标准定义:
(Inversion of Control)
中文译为: 控制反转
IOC的基本概念是:不创建对象,但是描述创建它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务。容器负责将这些联系在一起。