隨筆 - 81  文章 - 1033  trackbacks - 0
          <2007年1月>
          31123456
          78910111213
          14151617181920
          21222324252627
          28293031123
          45678910

          在浮躁的年代里,我們進取心太切,患得患失;虛榮心太強,戰(zhàn)戰(zhàn)兢兢。一心爭強好勝,惟恐榜上無名。
          I think I can fly , and flying like a bird !
          程序員一名,已售出,缺貨中!

          我的郵件聯(lián)系方式

          用且僅用于MSN

          博客點擊率
          free web counter
          free web counter

          常用鏈接

          留言簿(36)

          隨筆檔案

          搜索

          •  

          積分與排名

          • 積分 - 187074
          • 排名 - 309

          最新評論

          閱讀排行榜

          評論排行榜

          摘自: http://news.csdn.net/n/20061228/100086.html

          這篇文章寫的很有意思,把晦澀難懂的術(shù)語用拍電影來表達(dá),效果很不錯,特此轉(zhuǎn)載。

          概述

          ??? IoC(反向控制:Inverse of Control)是Spring容器的底層核心功能,AOP功能、聲明事務(wù)等功能在此基礎(chǔ)上生根開花。但是IoC這個重要的概念卻比較晦澀隱諱,拐彎抹角,不容易讓人望文生義,不能不說是一大遺憾。不過IoC確實包括很多內(nèi)涵,它涉及到代碼解耦,設(shè)計模式優(yōu)化等問題的考量。
          2006年多部賀歲大片以讓人應(yīng)接不暇的頻率紛至沓來,其中張之亮的《墨攻》算是比較出彩的一部,講述了戰(zhàn)國時期墨家人革離幫助梁國反抗趙國侵略的個人英雄主義故事,恢宏壯闊,渾雄凝重的歷史場面相當(dāng)震撼。其中有一個場景:當(dāng)劉德華所飾的墨者革離到達(dá)梁國都城下,城上梁國守軍問:“來者何人?”,劉德華回答:“墨者革離!”,我們不妨用Java對這段“城門問對”的場景進行編劇并借由這個例子來理解IoC的內(nèi)涵。

          劇本和飾演者耦合
          ?
          MoAttack代表《墨攻》的劇本,cityGetAsk()代表“城門問對”這段劇情,LiuDeHua是具體飾演者劉天王:
          ??????????????????????????????? 代碼清單 1? MoAttack:通過演員安排劇本

          public class MoAttack { public void cityGateAsk(){ LiuDeHua ldh =new LiuDeHua(); ① 演員直接侵入劇本 ldh.responseAsk("墨者革離!"); } }
          ? 我們會發(fā)現(xiàn)以上劇本在①處,作為具體飾演者的劉德華直接侵入到劇本中,使劇本和演員直接耦合在一起:
          ???????????????????????

          ?????????????????????????????????????????????????? ??????? 圖 1 劇本和演員直接耦合
          ? 一個明智的編劇在劇情創(chuàng)作時應(yīng)圍繞故事的角色進行,而不應(yīng)考慮角色的具體飾演者,這樣才可能在劇本投拍時自由地遴選任何適合的演員,而非綁定在劉德華一人身上。通過以上的分析,我們知道需要為該劇本主人公革離定義一個接口,以角色進行劇情安排,飾演者實現(xiàn)角色的接口:
          ??????????????? 代碼清單 2 MoAttack:引入劇本角色

          publicclass MoAttack...{ publicvoid cityGateAsk() ...{ GeLi geli =new LiuDeHua(); ① 引入革離角色接口 geli.responseAsk("墨者革離!"); ② 通過接口開展劇情 } }


          ??? 在①處引入了劇本的角色——革離,劇本的情節(jié)通過角色展開,在拍攝時角色的事跡由演員表現(xiàn),如②處所示。因此墨攻、革離、劉德華三者的類圖關(guān)系如圖 2所示:
          ??


          ??? 我們希望劇本和演員無關(guān),可是,在圖2中,我們看到MoAttack同時依賴于GeLi接口和LiuDeHua類,并沒有達(dá)到我們所期望的劇本僅依賴于角色的目的。可是角色最終又必須通過具體的演員才能完成拍攝,如何將讓LiuDeHua和劇本無關(guān)而又能完成GeLi的具體動作呢?當(dāng)然是在影片投拍時,導(dǎo)演將LiuDeHua安排在GeLi的角色上,通過導(dǎo)演之手將劇本、角色、飾演者裝配起來。


          ??????????????????????????????????????? 圖 3 劇本和飾演者解耦了
          ??? 通過引入導(dǎo)演,劇本和具體的飾演者解耦了,對應(yīng)到軟件中,導(dǎo)演象是一個裝配器,將具體的飾演者賦給了劇本的角色。
          現(xiàn)在我們可以反過來講解IoC的概念了。IoC(Inverse of Control)的字面意思是控制反轉(zhuǎn),它包括兩個層面的內(nèi)容:其一是“控制”,其二是“反轉(zhuǎn)”,到底是什么東西的控制被反轉(zhuǎn)了呢?對應(yīng)到前面的例子,“控制”是指GeLi角色扮演者的選擇控制權(quán),“反轉(zhuǎn)”是指這種選擇控制權(quán)從《墨攻》劇本中移除,轉(zhuǎn)交到導(dǎo)演的手中。對于程序來說,即是某一接口具體實現(xiàn)類的選擇控制權(quán)從客戶類中移除,轉(zhuǎn)交給第三方來確定,客戶類不知道是哪個具體的實現(xiàn)類,它通過接口方法對實現(xiàn)類進行調(diào)用。

          ??? 因為IoC確實不夠開門見山,因此業(yè)界曾進行了廣泛的討論,最終軟件界的泰斗級人物Martin Fowler提出了DI(依賴注入:Dependency Injection)的概念,即將客戶類對接口實現(xiàn)類的依賴關(guān)系由第三方(容器或協(xié)作類)注入,以移除客戶類對具體接口實現(xiàn)類的依賴。“依賴注入”的概念顯然比“控制反轉(zhuǎn)”直接達(dá)意,易于理解。

          IoC的三種類型

          ? 從注入方法上看,主要可以劃分為三種的注入類型,分別是構(gòu)造函數(shù)注入、屬性注入和接口注入,Spring支持構(gòu)造函數(shù)注入和屬性注入。下面我們繼續(xù)使用以上的例子說明這三種注入方法的區(qū)別。

          ■ 構(gòu)造函數(shù)注入
          ??? 我們通過客戶類的構(gòu)造函數(shù),將接口實現(xiàn)類通過接口變量傳入,如代碼清單 3 3所示:
          ???????????????????? 代碼清單 3 MoAttack:通過構(gòu)造函數(shù)注入革離扮演者

          ?

          publicclass MoAttack { private GeLi geli; public MoAttack(GeLi geli){ ① 注入革離的具體扮演者 this.geli = geli; }publicvoid cityGateAsk() { geli.responseAsk(“墨者革離!”); } }

          ???? MoAttack的構(gòu)造函數(shù)不關(guān)心具體是誰扮演革離這個角色,只要在①處傳入的扮演者按劇本要求完成角色功能即可。
          角色的具體扮演者由導(dǎo)演來安排,如代碼清單 3 4所示:
          ??????????????????????????????????????????? 代碼清單 4 Director:通過構(gòu)造函數(shù)注入革離扮演者

          publicclass Director { publicvoid direct(){ GeLi geli =new LiuDeHua(); ① 指定角色的扮演者 MoAttack moAttack =new MoAttack(geli); ② 注入具體扮演者到劇本中 moAttack.cityGateAsk(); } }

          ??? 在①處,導(dǎo)演安排劉德華飾演革離的角色,并在②處,將劉德華“注入”到墨攻的劇本中,然后開始“城門問答”劇段的演出工作。
          ??
          ■ 屬性注入
          ???? 有時,導(dǎo)演會發(fā)現(xiàn),雖然革離是影片《墨攻》的第一主人公,但并非每場戲都需要革離的出現(xiàn),通過構(gòu)造函數(shù)方式注入顯得很不妥當(dāng),在這種情況下,可以使用屬性注入進行改造。屬性注入通過setter方法完成客戶類所需依賴的注入,更靈活,更方便。
          ??????????????????? 代碼清單 5 MoAttack:通過setter方法注入革離扮演者

          publicclass MoAttack { private GeLi geli; publicvoid setGeli(GeLi geli) { ① 屬性注入方法 this.geli = geli; }publicvoid cityGateAsk() { geli.responseAsk("墨者革離"); } }

          ?? MoAttack在①處為geli屬性提供一個setter方法,以便讓導(dǎo)演在拍需要革離的戲時才將注入geli的具體扮演者,而不需要劉德華從頭到尾跟著墨攻劇組跑。
          ????? 代碼清單 6 Director:通過setter方法注入革離扮演者

          publicclass Director { publicvoid direct(){ GeLi geli =new LiuDeHua(); MoAttack moAttack =new MoAttack(); moAttack.setGeli(geli); ① 調(diào)用屬性setter方法注入 moAttack.cityGateAsk(); } }

          ??? 和通過構(gòu)造函數(shù)注入革離扮演者不同,在實例化MoAttack時,并未指定任何扮演者,而是在實例化MoAttack后,調(diào)用其setGeli()方法注入扮演者。按照類似的方式,我們還可以為劇本中其他如巷淹中,梁王等角色分別提供注入的setter方法,導(dǎo)演即可以根據(jù)所拍劇段的不同,注入所需要的角色了。

          ■ 接口注入
          ???? 將客戶類所有注入的方法抽取到一個接口中,客戶類通過實現(xiàn)這一接口提供注入的方法。為了采取接口注入的方式,需要聲明一個額外的接口:

          publicinterface ActorArrangable { void injectGeli(GeLi geli); }

          ??? 然后,MoAttack實現(xiàn)這個接口并實現(xiàn)接口中的方法:
          ???????????? 代碼清單 7 MoAttack:通過接口方法注入革離扮演者

          publicclass MoAttack implements ActorArrangable { private GeLi geli; publicvoid injectGeli (GeLi geli) { ① 實現(xiàn)接口方法 this.geli = geli; }publicvoid cityGateAsk() { geli.responseAsk("墨者革離"); } }

          Director通過ActorArrangable的injectGeli()方法完成扮演者的注入工作。
          ?? 代碼清單 8 Director:通過接口方法注入革離扮演者

          publicclass Director { publicvoid direct(){ GeLi geli =new LiuDeHua(); MoAttack moAttack =new MoAttack(); moAttack. injectGeli (geli); moAttack.cityGateAsk(); } }

          ?? 由于通過接口注入需要額外聲明一個接口,增加了類的數(shù)目,而且它的效果和屬性注入并無本質(zhì)區(qū)別,因此我們不提倡這種方式。

          通過容器完成依賴關(guān)系的建立

          ??? 雖然MoAttack和LiuDeHua實現(xiàn)了解耦,無需關(guān)注實現(xiàn)類的實例化工作,但這些工作在代碼中依然存在,只是轉(zhuǎn)移到Director中而已,導(dǎo)致導(dǎo)演的權(quán)力非常大,潛規(guī)則不斷滋生。假設(shè)某一制片人想改變這一局面,在相中某個劇本后,通過一個“海選”或者第三公正中介來選擇導(dǎo)演、演員,讓他們各司其職,那劇本、導(dǎo)演、演員就都實現(xiàn)解耦了。
          所謂媒體“海選”和中介機構(gòu)在程序領(lǐng)域即是一個第三方容器,它幫助我們完成類的初始化和裝配工作,讓我們從這些底層的實現(xiàn)類實例化,依賴關(guān)系的裝配中脫離出來,專注于更有意思的業(yè)務(wù)代碼的編寫工作,那確實是挺愜意的事情。Spring就是這樣一個容器,它通過配置文件描述類之間的依賴關(guān)系,下面是Spring配置文件的對以上實例進行配置的樣式代碼:

          <beans><bean id="geli"class="com.baobaotao.LiuDeHua"></bean><bean id="moAttack"class=" com.baobaotao.MoAttack"><property name="geli"><ref bean="geli"/></property></bean></beans>

          ???? 通過new XmlBeanFactory(“beans.xml”)等方式即可啟動容器,在容器啟動時,Spring根據(jù)配置文件的描述信息,通過Java的反射機制自動實例化Bean并完成依賴關(guān)系的建立,從容器中即可返回準(zhǔn)備就緒的Bean實例,以待后續(xù)的使用。

          小結(jié)

          ??? 隨著Spring的廣泛應(yīng)用,IoC的概念被越來越多的提及,可是很多說者因為IoC本身的晦澀往往并不清楚其中的意義,我們通過時下叫座的賀歲大片《墨攻》來解釋IoC的概念,相信對加深I(lǐng)oC概念的理解有所補益。

          posted on 2007-01-11 23:08 cresposhi 閱讀(1066) 評論(19)  編輯  收藏

          FeedBack:
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-01-17 15:36 梅穎
          看不懂,幸虧我冒搞這個,好累人啊看的我  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-01-31 11:42 kirari_wxy
          施偉是不是武漢人?怎么你老婆的留言都是武漢話?呵呵 看著親切。  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-01-31 11:51 梅穎
          是啊是啊,我是正宗的武漢人,他才不是列,他是武漢的女婿,呵呵,你是武漢的么?你好你好,不在武漢呀?  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-01-31 12:10 kirari_wxy
          我是標(biāo)準(zhǔn)的武漢人哦,呵呵,不過來上海2年多了。  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-01-31 13:53 梅穎
          那上海好不好列?  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-01-31 14:00 kirari_wxy
          當(dāng)然好,不過吃的東西不行,冇得一個東西好吃,這是所有外地人的痛苦。  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-01-31 14:03 梅穎
          自己做飯啊,我在深圳就是自己做飯吃列,到外面吃的少  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-01-31 14:13 kirari_wxy
          不會咧,我從來冇進過廚房,以前都是在外面吃,現(xiàn)在合租以后有同事做飯。  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-01-31 14:19 梅穎
          你還一點個學(xué)習(xí)的精神都冒的列,果然是武漢的兒子牙啊  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-01-31 14:27 kirari_wxy
          一個人住做飯也太麻煩了撒  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-01-31 14:44 梅穎
          那你先說說我們要準(zhǔn)備什么,過去之前,呵呵,都老人了,快點建議一哈,還老鄉(xiāng)列,要不過去給你代點熱干面,呵呵  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-01-31 14:57 kirari_wxy
          沒什么,多帶點錢就可以了,剛來的話用錢的地方比較多,特別是租房。各種證件帶齊,戶口之類不能帶的至少要帶上復(fù)印件,如果進比較大的公司,要出國出差的話,提前辦個護照也行,來了再回去辦就麻煩了。  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-01-31 15:02 梅穎
          這么麻煩啊,天哪,那我先去辦一個,哈哈  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-01-31 21:07 施偉
          真是老鄉(xiāng)見老鄉(xiāng)兩眼淚汪汪啊 你們。。。 呵呵
          繼續(xù)繼續(xù) 我隱身先   回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-02-01 12:45 梅穎
          呵呵,我覺得墨攻還可以(換話題)!  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-02-02 12:32 小祝
          ...什么呀,成聊天室了.哈哈,技術(shù)問題要嚴(yán)肅.寫的不錯,可惜我看不懂...  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-02-02 15:13 梅穎
          那你怎么知道寫的可以,切,你才是侮辱技術(shù)問題列,呵呵,還說我們  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-02-02 20:44 施偉
          真是口無遮攔的老婆,哎。。。
          我的朋友都逃不過她的魔掌。。。呵呵  回復(fù)  更多評論
            
          # re: 看《墨攻》理解IoC—Spring底層核心 (寫的很有意思)【 轉(zhuǎn)載】 2007-02-02 22:56 梅穎
          呵呵我成東方不敗了,人妖?
            回復(fù)  更多評論
            

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 沙田区| 信丰县| 兰坪| 铁岭县| 太保市| 老河口市| 方城县| 左权县| 福海县| 朝阳区| 淄博市| 绥阳县| 乌苏市| 平乡县| 临安市| 福州市| 孟津县| 句容市| 太谷县| 靖远县| 依兰县| 轮台县| 横山县| 石阡县| 抚州市| 瑞金市| 英吉沙县| 乡城县| 济南市| 南郑县| 枞阳县| 米泉市| 朝阳市| 岳阳县| 岳普湖县| 吉安县| 英德市| 城口县| 哈密市| 长治市| 巴林右旗|