工廠模式的升級 IOC 依賴注入 控制反轉

依賴注入(Dependency Injection)和控制反轉(Inversion of Control)是同一個概念。具體含義是:當某個角色(多是一個Java實例,調用者)須要另外一個角色(另外一個Java實例,被調用者)的協助時,在 傳統的程序設計過程當中,一般由調用者來建立被調用者的實例。但在Spring裏,建立被調用者的工做再也不由調用者來完成,所以稱爲控制反轉;建立被調用者 實例的工做一般由Spring容器來完成,而後注入調用者,所以也稱爲依賴注入。java


總結

(1)也許有人說,IoC和工廠模式不是同樣的做用嗎,用IoC好象還麻煩一點。

舉個例子,若是用戶需求發生變化,要把Chinese類修改一下。那麼前一種工廠模式,就要更改Factory類的方法,而且從新編譯佈署。而IoC只需 要將class屬性改變一下,而且因爲IoC利用了Java反射機制,這些對象是動態生成的,這時咱們就能夠熱插撥Chinese對象(沒必要把原程序中止 下來從新編譯佈署,java特性 須要從新編譯

(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方式等。
如今,低侵入性彷佛也成了斷定一個框架的實現技術好壞的標準之一。spring

一、以下圖所示有三個類,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("美國人以車代步,有四肢退化的趨勢");
}
}
二、對以上對象採用工廠模式的用法以下

建立一個工廠類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();
}
}
三、採用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 id="Chinese" class="cn.com.chengang.spring.Chinese"/>
<bean id="American" class="cn.com.chengang.spring.American"/>
</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="Chinese" class="cn.com.chengang.spring.Chinese"/>            
id就是ctx.getBean的參數值,一個字符串。class就是一個類(包名+類名)。而後在ClientTest類裏得到Chinese對象就是這麼一句

human = (Human) ctx.getBean(CHINESE);            
由於getBean方法返回的是Object類型,因此前面要加一個類型轉換框架

相關文章
相關標籤/搜索