二、 IOC使用的背景
在我们日常的设计中,类与类之间存在着千丝万缕的关系,如果两个类存在着强耦合关系,那么在维护时,一个类的修改很可能会牵动另一个类的关联修改,从而使得我们的维护工作步履维艰。下面让我们来看这样的一个强耦合反面例子。
首先我们建立一个Chinese.java类,该类的sayHelloWorld(String name)方法,用中文对名为name的人问好,其内容如下:
package org.amigo.reflection;
/**
*中国人类.
*@author<a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
*Creationdate:2007-10-2-上午10:37:17
*/
publicclass Chinese {
/**
*用中文对某人问好.
*@paramname姓名
*/
publicvoid sayHelloWorld(String name) {
String helloWorld = "你好," + name;
System.out.println(helloWorld);
}
}
下面我们接着建立一个American.java类,该类的sayHelloWorld(String name)方法,用英文对名为name的人问好,其内容如下:
package org.amigo.reflection;
/**
*美国人类.
*@author<a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
*@version1.0
*Creationdate:2007-10-2-上午10:41:27
*/
publicclass American {
/**
*用英文对某人问好.
*@paramname姓名
*/
publicvoid sayHelloWorld(String name) {
String helloWorld = "Hello," + name;
System.out.println(helloWorld);
}
}
最后我们编写一个测试类对这两个类的sayHelloWorld(String name)方法进行测试,下面是该类的内容:
package org.amigo.reflection;
/**
*HelloWorld测试.
*@author<a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
*Creationdate:2007-10-2-上午10:45:13
*/
publicclass HelloWorldTest {
/**
*测试Chinese和American的sayHelloWorld()方法.
*@paramargs
*@author<a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
*Creationdate:2007-10-2-上午10:43:51
*/
publicstaticvoid main(String[] args) {
Chinese chinese = new Chinese();
chinese.sayHelloWorld("阿蜜果");
American american = new American();
american.sayHelloWorld("Amigo");
}
}
观察HelloWorldTest我们可以很清楚的看到,该类与Chinese.java类和American.java类都存在强耦合关系。
上面的例子让我们想到的是在N年以前,当我们需要某个东西时,我们一般是自己制造。但是当发展到了一定的阶段后,工厂出现了,我们可以工厂中购买我们需要的东西,这极大的方便了我们。在上例中,我们都是通过new来创建新的对象,在开发中,这种强耦合关系是我们所不提倡的,那么我们应该如何来实现这个例子的解耦呢?我们接着想到了使用工厂模式,我们需要新建一个工厂类来完成对象的创建,并采用依赖接口的方式,此时需要对代码进行如下修改:
首先建立接口类Human.java,其内容如下。
package org.amigo.reflection;
/**
* 人类接口类.
* @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
* Creation date: 2007-10-2 - 上午11:04:56
*/
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工厂类,其内容为:
package org.amigo.reflection;
/**
* 工厂类.
* @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
* Creation date: 2007-10-2 - 上午11:09:30
*/
public class HumanFactory {
/**
* 通过类型字段获取人的相应实例
* @param type 类型
* @return 返回相应实例
*/
public Human getHuman(String type) {
if ("chinese".equals(type)) {
return new Chinese();
} else {
return new American();
}
}
}
最后我们还需要修改测试类HelloWorld.java类,修改后的内容如下:
package org.amigo.reflection;
/**
* HelloWorld测试.
* @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
* Creation date: 2007-10-2 - 上午10:45:13
*/
public class HelloWorldTest {
/**
* 测试sayHelloWorld()方法.
* @param args
* @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
* Creation date: 2007-10-2 - 上午10:43:51
*/
public static void main(String[] args) {
HumanFactory factory = new HumanFactory();
Human human1 = factory.getHuman("chinese");
human1.sayHelloWorld("阿蜜果");
Human human2 = factory.getHuman("american");
human2.sayHelloWorld("Amigo");
}
}
观察此例我们可以看到,该类不再与具体的实现类Chinese和American存在耦合关系,而只是与它们的接口类Human存在耦合关系,具体对象的获取只是通过传入字符串来获取,很大程度上降低了类与类之间的耦合性。
但是我们还是不太满足,因为还需要通过chinese和american在类中获取实例,那么当我们需要修改时实现时,我们还需要在类中修改这些字符串,那么还有没有更好的办法呢?让我们在下节中进行继续探讨。