Spring IOC 與工廠模式

Spring的模塊化是很強的,各個功能模塊都是獨立的,我們可以選擇的使用。這一章先從Spring的IoC開始。所謂IoC就是一個用XML來定義生成對象的模式,我們看看如果來使用的。


   數據模型


   1、如下圖所示有三個類,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("美國人以車代步,有四肢退化的趨勢");    
}    
}   
 


2、對以上對象採用工廠模式的用法如下


   創建一個工廠類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();    
}    
}   
 


3、採用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類型,所以前面要加一個類型轉換。


   總結


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


   舉個例子,如果用戶需求發生變化,要把Chinese類修改一下。那麼前一種工廠模式,就要更改Factory類的方法,並且重新編譯佈署。而IoC只需要將class屬性改變一下,並且由於IoC利用了Java反射機制,這些對象是動態生成的,這時我們就可以熱插撥Chinese對象(不必把原程序停止下來重新編譯佈署)


   (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方式等。
現在,低侵入性似乎也成了判定一個框架的實現技術好壞的標準之一。


   (5)關於bean.xml的用法


   bean.xml的用法還有很多,其中內容是相當豐富的。假設Chinese類裏有一個humenName屬性(姓名),那麼原的bean.xml修改如下。此後生成Chinese對象時,“陳剛”這個值將自動設置到Chinese類的humenName屬性中。而且由於singleton爲true這時生成Chinese對象將採用單例模式,系統僅存在一個Chinese對象實例。


<?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" singleton="true">
<property name="humenName">
<value>陳剛</value>
</property>
</bean>
<bean id="American" class="cn.com.chengang.spring.American"/>
</beans> 


   關於bean.xml的其它用法,不再詳細介紹了,大家自己拿Spring的文檔一看就明白了。


 Spring能有效地組織J2EE應用各層的對象。不管是控制層的Action對象,還是業務層的Service對象,還是持久層的DAO對象,都可在Spring的管理下有機地協調、運行。Spring將各層的對象以鬆耦合的方式組織在一起,Action對象無須關心Service對象的具體實現,Service對象無須關心持久層對象的具體實現,各層對象的調用完全面向接口。當系統需要重構時,代碼的改寫量將大大減少。


  上面所說的一切都得宜於Spring的核心機制,依賴注入。依賴注入讓bean與bean之間以配置文件組織在一起,而不是以硬編碼的方式耦合在一起。理解依賴注入


  依賴注入(Dependency Injection)和控制反轉(Inversion of Control)是同一個概念。具體含義是:當某個角色(可能是一個Java實例,調用者)需要另一個角色(另一個Java實例,被調用者)的協助時,在傳統的程序設計過程中,通常由調用者來創建被調用者的實例。但在Spring裏,創建被調用者的工作不再由調用者來完成,因此稱爲控制反轉;創建被調用者實例的工作通常由Spring容器來完成,然後注入調用者,因此也稱爲依賴注入。


  不管是依賴注入,還是控制反轉,都說明Spring採用動態、靈活的方式來管理各種對象。對象與對象之間的具體實現互相透明。在理解依賴注入之前,看如下這個問題在各種社會形態裏如何解決:一個人(Java實例,調用者)需要一把斧子(Java實例,被調用者)。


  (1)原始社會裏,幾乎沒有社會分工。需要斧子的人(調用者)只能自己去磨一把斧子(被調用者)。對應的情形爲:Java程序裏的調用者自己創建被調用者。


  (2)進入工業社會,工廠出現。斧子不再由普通人完成,而在工廠裏被生產出來,此時需要斧子的人(調用者)找到工廠,購買斧子,無須關心斧子的製造過程。對應Java程序的簡單工廠的設計模式。


  (3)進入“按需分配”社會,需要斧子的人不需要找到工廠,坐在家裏發出一個簡單指令:需要斧子。斧子就自然出現在他面前。對應Spring的依賴注入。


  第一種情況下,Java實例的調用者創建被調用的Java實例,必然要求被調用的Java類出現在調用者的代碼裏。無法實現二者之間的鬆耦合。


  第二種情況下,調用者無須關心被調用者具體實現過程,只需要找到符合某種標準(接口)的實例,即可使用。此時調用的代碼面向接口編程,可以讓調用者和被調用者解耦,這也是工廠模式大量使用的原因。但調用者需要自己定位工廠,調用者與特定工廠耦合在一起。


  第三種情況下,調用者無須自己定位工廠,程序運行到需要被調用者時,系統自動提供被調用者實例。事實上,調用者和被調用者都處於Spring的管理下,二者之間的依賴關係由Spring提供。


  所謂依賴注入,是指程序運行過程中,如果需要調用另一個對象協助時,無須在代碼中創建被調用者,而是依賴於外部的注入。Spring的依賴注入對調用者和被調用者幾乎沒有任何要求,完全支持對POJO之間依賴關係的管理。依賴注入通常有兩種:




原文鏈接:http://java.banzhu.net/article/java-4-158422.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章