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控制。