Inversion of Control (IoC),直接翻译过来是控制反转。那么到底是什么控制被反转了呢?传统的,一个对象A如果需要使用对象B(B是A的依赖),那么A要负责去获取B的引用,这样会导致高耦合、难以测试的代码。所谓的控制反转,就是A不负责去获取B的引用,而是由外部实体(负责安排、调整系统中的各个对象的外部实体)来给它它所需要的依赖。所以,控制反转又叫做依赖注入(dependency injection)。
IoC的应用示例
例如,实现一个男人给一个女人送花的程序。
首先定义花的接口。
public interface Flower {
public String getName();
}
然后实现一种特定的花——玫瑰花。
public class Rose implements Flower{
private String name = "Rose";
public Rose() {
}
public String getName(){
return name;
}
}
然后是男人和女人。
public class Man{
public Man() {
}
public void sendFlower(Woman woman){
Flower flower = new Rose();
woman.recieveFlower(flower);
}
}
public class Woman {
public Woman() {
}
public void recieveFlower(Flower flower){
if ("Rose".equals(flower.getName())){
System.out.println("Oh, thanks!” + flower.getName() + “ is my favorate flower!");
}
else{
System.out.println("Thanks! What's a beautiful " + flower.getName());
}
}
}
最后是主应用程序。
public class HelloApp {
public HelloApp() {
}
public static void main(String[] args) throws Exception{
Man man = new Man();
Woman woman = new Woman();
man.sendFlower(woman);
}
}
看起来没有什么问题吧,程序运行也是正常的。但是,如果你想测试一下送百合的效果,怎么办?
首先,需要添加一个百合类。
public class Lily implements Flower{
private String name = "Lily";
public Lily() {
}
public String getName(){
return name;
}
}
但是这个还是不够的,你还需要修改Man类。因为Man现在和Rose是紧耦合的。修改如下:
public class Man{
public Man() {
}
public void sendFlower(Woman woman){
Flower flower = new Lily();
woman.recieveFlower(flower);
}
}
每次你需要换一种花的时候,都需要重新修改、编译Man类。
如果使用Spring的IoC,则可以将Man函数修改如下:
import java.io.FileInputStream;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.io.InputStreamResource;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.Resource;
public class Man{
public Man() {
}
public void sendFlower(Woman woman) throws Exception{
FileInputStream fileInputStream = new FileInputStream("hello.xml");
Resource resource = new InputStreamResource(fileInputStream);
BeanFactory factory = new XmlBeanFactory(resource);
Flower flower = (Flower)factory.getBean("flower");
woman.recieveFlower(flower);
}
}
hello.xml文件如下:
<?xml version="1.0"?>
<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="flower"
class = "chapter01.hello.Rose">
</bean>
</beans>
如果你需要送百合,只需要将xml文件中的<bean id="flower" class = "chapter01.hello.Rose">改成<bean id="flower" class = "chapter01.hello.Lily">,不需要重新编译程序。
再最后的Man的版本中,Man获得的是一朵花,这朵花是由Spring框架给他的。也就是说,具体获得什么花,是由Spring框架控制,而不是由Man控制。