




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、反轉(zhuǎn)控制容器與依賴注入模式在企業(yè)級(jí)java 的世界里存在一個(gè)有趣的現(xiàn)象:有很多人投入很多精力來(lái)研究主流j2ee 技術(shù)的替代品自然,這大多發(fā)生在open source 社群。在很大程度上,這可以看作是開發(fā)者對(duì)主流j2ee 技術(shù)的笨重和復(fù)雜作出的回應(yīng),但其中的確有很多極富創(chuàng)意的想法,的確提供了一些可供選擇的方案。j2ee 開發(fā)者常遇到的一個(gè)問(wèn)題就是如何組裝不同的程序元素:如果web 控制器體系結(jié)構(gòu)和數(shù)據(jù)庫(kù)接口是由不同的團(tuán)隊(duì)所開發(fā)的,彼此幾乎一無(wú)所知,你應(yīng)該如何讓它們配合工作?很多框架嘗試過(guò)解決這個(gè)問(wèn)題,有幾個(gè)框架索性朝這個(gè)方向發(fā)展,提供了更通用的”組裝各層組件”的方案。這樣的框架通常被稱為”輕量級(jí)
2、容器”,picocontainer 和spring 都在此列。在這些容器背后,一些有趣的設(shè)計(jì)原則發(fā)揮著作用。這些原則已經(jīng)超越了特定容器的限制,甚至已經(jīng)超越了java 平臺(tái)的范疇。在本文中,我就要初步揭示這些原則。我使用的范例是java 代碼,但正如我的大多數(shù)文章一樣,這些原則也同樣適用于其它的oo 環(huán)境,特別是.net。組件和服務(wù)這樣的話題立即將我拖進(jìn)了一個(gè)棘手的術(shù)語(yǔ)問(wèn)題:如何區(qū)分”服務(wù)”(service)和”組件”(component)?你可以毫不費(fèi)力地找出關(guān)于這兩個(gè)詞定義的長(zhǎng)篇大論。有鑒于此,對(duì)于這兩個(gè)遭到了嚴(yán)重濫用的詞匯,我將首先說(shuō)明它們?cè)诒疚闹械挠梅?。在本文中,”組建”指的是一個(gè)軟件單
3、元,它將被作者無(wú)法控制的其他應(yīng)用程序使用,但后者不能對(duì)組件進(jìn)行修改。也就是說(shuō),使用一個(gè)組件的應(yīng)用程序不能修改組件的源代碼,但可以通過(guò)作者預(yù)留的某種途徑對(duì)其進(jìn)行擴(kuò)展,以改變組件的行為。服務(wù)和組件有某種相似之處:它們都將被外部的應(yīng)用程序使用。在我看來(lái),兩者之間最大的差異在于:組件是在本地使用的(例如jar 文件、程序集、dll、或者源碼導(dǎo)入);而服務(wù)是要通過(guò)同步或異步的遠(yuǎn)程接口來(lái)遠(yuǎn)程使用的(例如web service、消息系統(tǒng)、rpc,或者socket)。在本文中,我將主要使用“服務(wù)”這個(gè)詞,但文中的大多數(shù)邏輯也同樣適用于本地組件。實(shí)際上,為了方便地訪問(wèn)遠(yuǎn)程服務(wù),你往往需要某種本地組件框架。不過(guò),
4、“組件或者服務(wù)”這樣一個(gè)詞組實(shí)在太麻煩了,而且“服務(wù)”這個(gè)詞當(dāng)下也很流行,所以本文將用”服務(wù)”指代這兩者。一個(gè)簡(jiǎn)單的例子為了更好地說(shuō)明問(wèn)題,我要引入一個(gè)例子。和我以前用的所有例子一樣,這是一個(gè)超級(jí)簡(jiǎn)單的例子:它非常小,小得有點(diǎn)不夠真實(shí),但足以幫助你看清其中的道理,而不至于陷入真實(shí)例子的泥潭中無(wú)法自拔。在這個(gè)例子中,我編寫了一個(gè)組件,用于提供一份電影清單,清單上列出的影片都是由一位特定的導(dǎo)演執(zhí)導(dǎo)的。實(shí)現(xiàn)這個(gè)偉大的功能只需要一個(gè)方法:class movielister. public movie moviesdirectedby(string arg) list allmovies = finde
5、r.findall(); for (iterator it = allmovies.iterator(); it.hasnext();) movie movie = (movie) it.next(); if (!movie.getdirector().equals(arg) it.remove(); return (movie) allmovies.toarray(new movieallmovies.size();這個(gè)功能的實(shí)現(xiàn)極其簡(jiǎn)單:moviesdirectedby 方法首先請(qǐng)求finder(影片搜尋者)對(duì)象(我們稍后會(huì)談到這個(gè)對(duì)象)返回后者所知道的所有影片,然后遍歷finder 對(duì)象
6、返回的清單,并返回其中由特定的某個(gè)導(dǎo)演執(zhí)導(dǎo)的影片。非常簡(jiǎn)單,不過(guò)不必?fù)?dān)心,這只是整個(gè)例子的腳手架罷了。我們真正想要考察的是finder對(duì)象,或者說(shuō),如何將movielister對(duì)象與特定的finder對(duì)象連接起來(lái)。為什么我們對(duì)這個(gè)問(wèn)題特別感興趣?因?yàn)槲蚁M厦孢@個(gè)漂亮的moviesdirectedby方法完全不依賴于影片的實(shí)際存儲(chǔ)方式。所以,這個(gè)方法只能引用一個(gè)finder對(duì)象,而finder對(duì)象則必須知道如何對(duì)findall 方法作出回應(yīng)。為了幫助讀者更清楚地理解,我給finder定義了一個(gè)接口:public interface moviefinder list findall();現(xiàn)在,兩
7、個(gè)對(duì)象之間基本沒(méi)有耦合關(guān)系。但是,當(dāng)我要實(shí)際尋找影片時(shí),就必須涉及到moviefinder 的某個(gè)具體子類。在這里,我把”涉及具體子類”的代碼放在movielister 類的構(gòu)造子中。class movielister. private moviefinder finder; public movielister() finder = new colondelimitedmoviefinder(movies1.txt); 這個(gè)實(shí)現(xiàn)類的名字就說(shuō)明:我將要從一個(gè)逗號(hào)分隔的文本文件中獲得影片列表。你不必操心具體的實(shí)現(xiàn)細(xì)節(jié),只要設(shè)想這樣一個(gè)實(shí)現(xiàn)類就可以了。現(xiàn)在,如果這個(gè)類只由我自己使用,一切都沒(méi)問(wèn)題。
8、但是,如果我的朋友嘆服于這個(gè)精彩的功能,也想使用我的程序,那又會(huì)怎么樣呢?如果他們也把影片清單保存在一個(gè)逗號(hào)分隔的文本文件中,并且也把這個(gè)文件命名為” movie1.txt ”,那么一切還是沒(méi)問(wèn)題。如果他們只是給這個(gè)文件改改名,我也可以從一個(gè)配置文件獲得文件名,這也很容易。但是,如果他們用完全不同的方式例如sql 數(shù)據(jù)庫(kù)、xml 文件、web service,或者另一種格式的文本文件來(lái)存儲(chǔ)影片清單呢?在這種情況下,我們需要用另一個(gè)類來(lái)獲取數(shù)據(jù)。由于已經(jīng)定義了moviefinder接口,我可以不用修改moviesdirectedby 方法。但是,我仍然需要通過(guò)某種途徑獲得合適的moviefind
9、er實(shí)現(xiàn)類的實(shí)例。圖1:”在movielister 類中直接創(chuàng)建moviefinder 實(shí)例”時(shí)的依賴關(guān)系figure 1: the dependencies using a simple creation in the lister class圖1 展現(xiàn)了這種情況下的依賴關(guān)系:movielister 類既依賴于moviefinder接口,也依賴于具體的實(shí)現(xiàn)類。我們當(dāng)然希望movielister 類只依賴于接口,但我們要如何獲得一個(gè)moviefinder子類的實(shí)例呢?在patterns of enterprise application architecture 一書中,我們把這種情況稱為”插
10、件”(plugin):moviefinder的實(shí)現(xiàn)類不是在編譯期連入程序之中的,因?yàn)槲也⒉恢牢业呐笥褧?huì)使用哪個(gè)實(shí)現(xiàn)類。我們希望movielister 類能夠與moviefinder的任何實(shí)現(xiàn)類配合工作,并且允許在運(yùn)行期插入具體的實(shí)現(xiàn)類,插入動(dòng)作完全脫離我(原作者)的控制。這里的問(wèn)題就是:如何設(shè)計(jì)這個(gè)連接過(guò)程,使movielister 類在不知道實(shí)現(xiàn)類細(xì)節(jié)的前提下與其實(shí)例協(xié)同工作。將這個(gè)例子推而廣之,在一個(gè)真實(shí)的系統(tǒng)中,我們可能有數(shù)十個(gè)服務(wù)和組件。在任何時(shí)候,我們總可以對(duì)使用組件的情形加以抽象,通過(guò)接口與具體的組件交流(如果組件并沒(méi)有設(shè)計(jì)一個(gè)接口,也可以通過(guò)適配器與之交流)。但是,如果我們希望
11、以不同的方式部署這個(gè)系統(tǒng),就需要用插件機(jī)制來(lái)處理服務(wù)之間的交互過(guò)程,這樣我們才可能在不同的部署方案中使用不同的實(shí)現(xiàn)。所以,現(xiàn)在的核心問(wèn)題就是:如何將這些插件組合成一個(gè)應(yīng)用程序?這正是新生的輕量級(jí)容器所面臨的主要問(wèn)題,而它們解決這個(gè)問(wèn)題的手段無(wú)一例外地是控制反轉(zhuǎn)(inversion of control)模式??刂品崔D(zhuǎn)幾位輕量級(jí)容器的作者曾驕傲地對(duì)我說(shuō):這些容器非常有用,因?yàn)樗鼈儗?shí)現(xiàn)了”控制反轉(zhuǎn)”。這樣的說(shuō)辭讓我深感迷惑:控制反轉(zhuǎn)是框架所共有的特征,如果僅僅因?yàn)槭褂昧丝刂品崔D(zhuǎn)就認(rèn)為這些輕量級(jí)容器與眾不同,就好像在說(shuō)”我的轎車是與眾不同的,因?yàn)樗兴膫€(gè)輪子”。問(wèn)題的關(guān)鍵在于:它們反轉(zhuǎn)了哪方面的控制
12、?我第一次接觸到的控制反轉(zhuǎn)針對(duì)的是用戶界面的主控權(quán)。早期的用戶界面是完全由應(yīng)用程序來(lái)控制的,你預(yù)先設(shè)計(jì)一系列命令,例如”輸入姓名”、”輸入地址”等,應(yīng)用程序逐條輸出提示信息,并取回用戶的響應(yīng)。而在圖形用戶界面環(huán)境下,ui 框架將負(fù)責(zé)執(zhí)行一個(gè)主循環(huán),你的應(yīng)用程序只需為屏幕的各個(gè)區(qū)域提供事件處理函數(shù)即可。在這里,程序的主控權(quán)發(fā)生了反轉(zhuǎn):從應(yīng)用程序移到了ui框架。對(duì)于這些新生的容器,它們反轉(zhuǎn)的是”如何定位插件的具體實(shí)現(xiàn)”。在前面那個(gè)簡(jiǎn)單的例子中, movielister 類負(fù)責(zé)定位moviefinder 的具體實(shí)現(xiàn)它直接實(shí)例化后者的一個(gè)子類。這樣一來(lái),moviefinder 也就不成其為一個(gè)插件了,
13、因?yàn)樗⒉皇窃谶\(yùn)行期插入應(yīng)用程序中的。而這些輕量級(jí)容器則使用了更為靈活的辦法,只要插件遵循一定的規(guī)則,一個(gè)獨(dú)立的組裝模塊就能夠?qū)⒉寮木唧w實(shí)現(xiàn)”注入”到應(yīng)用程序中。因此,我想我們需要給這個(gè)模式起一個(gè)更能說(shuō)明其特點(diǎn)的名字”控制反轉(zhuǎn)”這個(gè)名字太寬泛了,常常讓人有些迷惑。與多位ioc 愛(ài)好者討論之后,我們決定將這個(gè)模式叫做”依賴注入”(dependency injection)。下面,我將開始介紹dependency injection 模式的幾種不同形式。不過(guò),在此之前,我要首先指出:要消除應(yīng)用程序?qū)Σ寮?shí)現(xiàn)的依賴,依賴注入并不是唯一的選擇,你也可以用service locator 模式獲得同樣的
14、效果。介紹完dependency injection 模式之后,我也會(huì)談到service locator 模式。依賴注入的幾種形式dependency injection 模式的基本思想是:用一個(gè)單獨(dú)的對(duì)象(裝配器)來(lái)獲得moviefinder的一個(gè)合適的實(shí)現(xiàn),并將其實(shí)例賦給movielister 類的一個(gè)字段。這樣一來(lái),我們就得到了圖2所示的依賴圖:圖2:引入依賴注入器之后的依賴關(guān)系figure 2: the dependencies for a dependency injector依賴注入的形式主要有三種,我分別將它們叫做構(gòu)造子注入(constructor injection)、設(shè)值方法
15、注入(setter injection)和接口注入(interface injection)。如果讀過(guò)最近關(guān)于ioc 的一些討論材料,你不難看出:這三種注入形式分別就是type 1 ioc(接口注入)、type 2 ioc(設(shè)值方法注入)和type 3 ioc(構(gòu)造子注入)。我發(fā)現(xiàn)數(shù)字編號(hào)往往比較難記,所以我使用了這里的命名方式。使用picocontainer 進(jìn)行構(gòu)造子注入首先,我要向讀者展示如何用一個(gè)名為picocontainer 的輕量級(jí)容器完成依賴注入。之所以從這里開始,主要是因?yàn)槲以趖houghtworks 公司的幾個(gè)同事在picocontainer 的開發(fā)社群中非?;钴S沒(méi)錯(cuò),也可以
16、說(shuō)是某種偏袒吧。picocontainer 通過(guò)構(gòu)造子來(lái)判斷”如何將moviefinder 實(shí)例注入movielister 類”。因此,movielister 類必須聲明一個(gè)構(gòu)造子,并在其中包含所有需要注入的元素:class movielister. public movielister(moviefinder finder) this.finder = finder; moviefinder 實(shí)例本身也將由picocontainer來(lái)管理,因此文本文件的名字也可以由容器注入:class colonmoviefinder. public colonmoviefinder(string file
17、name) this.filename = filename; 隨后,需要告訴picocontainer:各個(gè)接口分別與哪個(gè)實(shí)現(xiàn)類關(guān)聯(lián)、將哪個(gè)字符串注入moviefinder組件。private mutablepicocontainer configurecontainer() mutablepicocontainer pico = new defaultpicocontainer(); parameter finderparams = new constantparameter(movies1.txt); pico.registercomponentimplementation(movief
18、inder.class, colonmoviefinder.class, finderparams); pico.registercomponentimplementation(movielister.class); return pico; 這段配置代碼通常位于另一個(gè)類。對(duì)于我們這個(gè)例子,使用我的movielister 類的朋友需要在自己的設(shè)置類中編寫合適的配置代碼。當(dāng)然,還可以將這些配置信息放在一個(gè)單獨(dú)的配置文件中,這也是一種常見的做法。你可以編寫一個(gè)類來(lái)讀取配置文件,然后對(duì)容器進(jìn)行合適的設(shè)置。盡管picocontainer 本身并不包含這項(xiàng)功能,但另一個(gè)與它關(guān)系緊密的項(xiàng)目nanocont
19、ainer 提供了一些包裝,允許開發(fā)者使用xml 配置文件保存配置信息。nanocontainer能夠解析xml 文件,并對(duì)底下的picocontainer 進(jìn)行配置。這個(gè)項(xiàng)目的哲學(xué)觀念就是:將配置文件的格式與底層的配置機(jī)制分離開。使用這個(gè)容器,你寫出的代碼大概會(huì)是這樣:public void testwithpico() mutablepicocontainer pico = configurecontainer(); movielisterlister=(movielister)pico.getcomponentinstance(movielister.class); movie movi
20、es = lister.moviesdirectedby(sergio leone); assertequals(once upon a time in the west, movies0.gettitle(); 盡管在這里我使用了構(gòu)造子注入,實(shí)際上picocontainer 也支持設(shè)值方法注入,不過(guò)該項(xiàng)目的開發(fā)者更推薦使用構(gòu)造子注入。使用spring 進(jìn)行設(shè)值方法注入spring 框架是一個(gè)用途廣泛的企業(yè)級(jí)java 開發(fā)框架,其中包括了針對(duì)事務(wù)、持久化框架、web應(yīng)用開發(fā)和jdbc 等常用功能的抽象。和picocontainer 一樣,它也同時(shí)支持構(gòu)造子注入和設(shè)值方法注入,但該項(xiàng)目的開發(fā)者更
21、推薦使用設(shè)值方法注入恰好適合這個(gè)例子。為了讓movielister 類接受注入, 我需要為它定義一個(gè)設(shè)值方法, 該方法接受類型為moviefinder的參數(shù):class movielister. private moviefinder finder; public void setfinder(moviefinder finder) this.finder = finder; 類似地,在moviefinder的實(shí)現(xiàn)類中,我也文件名屬性定義了一個(gè)設(shè)值方法:class colonmoviefinder. public void setfilename(string filename) this.f
22、ilename = filename; 第三步是設(shè)定配置文件。spring 支持多種配置方式,你可以通過(guò)xml 文件進(jìn)行配置,也可以直接在代碼中配置。不過(guò),xml 文件是比較理想的配置方式。 movies1.txt 于是,測(cè)試代碼大概就像下面這樣:public void testwithspring() throws exception applicationcontext ctx = new filesystemxmlapplicationcontext(spring.xml); movielister lister = (movielister) ctx.getbean(movielist
23、er); movie movies = lister.moviesdirectedby(sergio leone); assertequals(once upon a time in the west, movies0.gettitle(); 接口注入除了前面兩種注入技術(shù),還可以在接口中定義需要注入的信息,并通過(guò)接口完成注入。avalon框架就使用了類似的技術(shù)。在這里,我首先用簡(jiǎn)單的范例代碼說(shuō)明它的用法,后面還會(huì)有更深入的討論。首先,我需要定義一個(gè)接口,組件的注入將通過(guò)這個(gè)接口進(jìn)行。在本例中,這個(gè)接口的用途是將一個(gè)moviefinder實(shí)例注入繼承了該接口的對(duì)象。public interfac
24、e injectfinder void injectfinder(moviefinder finder);然后,我使用類似的方法將文件名注入moviefinder的實(shí)現(xiàn)類:public interface injectfinderfilename void injectfilename (string filename);class colonmoviefinder implements moviefinder, injectfinderfilename. public void injectfilename(string filename) this.filename = filename;
25、現(xiàn)在,還需要用一些配置代碼將所有的組件實(shí)現(xiàn)裝配起來(lái)。簡(jiǎn)單起見,我直接在代碼中完成配置,并將配置好的movielister 對(duì)象保存在名為lister的字段中:class tester. private container container; private void configurecontainer() container = new container(); registercomponents(); registerinjectors(); container.start(); 這個(gè)配置器有兩個(gè)工作,以鍵值對(duì)的形式進(jìn)行組件的注冊(cè),如同其它例子中做的一樣。class tester. p
26、rivate void registercomponents() container.registercomponent(movielister, movielister.class); container.registercomponent(moviefinder, colonmoviefinder.class); 結(jié)下來(lái)的步驟是注冊(cè)用來(lái)注入依賴組件的”注入器”。每個(gè)注入的接口都需要一些注入代碼。在這里,我將”注入器”注冊(cè)到容器中。每個(gè)注入器實(shí)現(xiàn)一個(gè)注入器接口。class tester. private void registerinjectors() container.registeri
27、njector(injectfinder.class, container.lookup(moviefinder); container.registerinjector(injectfinderfilename.class, new finderfilenameinjector(); public interface injector public void inject(object target);class colonmoviefinder implements injector. public void inject(object target) (injectfinder) tar
28、get).injectfinder(this); class tester. public static class finderfilenameinjector implements injector public void inject(object target) (injectfinderfilename)target).injectfilename(movies1.txt); the tests then use the container.class ifacetester. public void testiface() configurecontainer(); movieli
29、ster lister = (movielister)container.lookup(movielister); movie movies = lister.moviesdirectedby(sergio leone); assertequals(once upon a time in the west, movies0.gettitle();容器使用了聲明的結(jié)構(gòu)注入來(lái)解除依賴,并通過(guò)注入器對(duì)現(xiàn)有依賴進(jìn)行注入。(該容器的實(shí)現(xiàn)我就不給讀者展示了,因?yàn)闆](méi)有什么價(jià)值。)inversion of control containers and the dependency injection patt
30、ernone of the entertaining things about the enterprise java world is the huge amount of activity in building alternatives to the mainstream j2ee technologies, much of it happening in open source. a lot of this is a reaction to the heavyweight complexity in the mainstream j2ee world, but much of it i
31、s also exploring alternatives and coming up with creative ideas. a common issue to deal with is how to wire together different elements: how do you fit together this web controller architecture with that database interface backing when they were built by different teams with little knowledge of each
32、 other.a number of frameworks have taken a stab at this problem, and several are branching out to provide a general capability to assemble components from different layers. these are often referred to as lightweight containers, examples include picocontainer, and spring.underlying these containers a
33、re a number of interesting design principles, things that go beyond both these specific containers and indeed the java platform. here i want to start exploring some of these principles. the examples i use are in java, but like most of my writing the principles are equally applicable to other oo envi
34、ronments, particularly .net.components and servicesthe topic of wiring elements together drags me almost immediately into the knotty terminology problems that surround the terms service and component. you find long and contradictory articles on the definition of these things with ease. for my purpos
35、es here are my current uses of these overloaded terms.i use component to mean a glob of software thats intended to be used, without change, by application that is out of the control of the writers of the component. by without change i mean that the using application doesnt change the source code of
36、the components, although they may alter the components behavior by extending it in ways allowed by the component writers. a service is similar to a component in that its used by foreign applications. the main difference is that i expect a component to be used locally (think jar file, assembly, dll,
37、or a source import). a service will be used remotely through some remote interface, either synchronous or asynchronous (eg web service, messaging system, rpc, or socket.)i mostly use service in this article, but much of the same logic can be applied to local components too. indeed often you need som
38、e kind of local component framework to easily access a remote service. but writing component or service is tiring to read and write, and services are much more fashionable at the moment.a naive exampleto help make all of this more concrete ill use a running example to talk about all of this. like al
39、l of my examples its one of those super-simple examples; small enough to be unreal, but hopefully enough for you to visualize whats going on without falling into the bog of a real example.in this example im writing a component that provides a list of movies directed by a particular director. this st
40、unningly useful function is implemented by a single method.class movielister. public movie moviesdirectedby(string arg) list allmovies = finder.findall(); for (iterator it = allmovies.iterator(); it.hasnext();) movie movie = (movie) it.next(); if (!movie.getdirector().equals(arg) it.remove(); return
41、 (movie) allmovies.toarray(new movieallmovies.size(); the implementation of this function is naive in the extreme, it asks a finder object (which well get to in a moment) to return every film it knows about. then it just hunts through this list to return those directed by a particular director. this
42、 particular piece of naivety im not going to fix, since its just the scaffolding for the real point of this article.the real point of this article is this finder object, or particularly how we connect the lister object with a particular finder object. the reason why this is interesting is that i wan
43、t my wonderful moviesdirectedby method to be completely independent of how all the movies are being stored. so all the method does is refer to a finder, and all that finder does is know how to respond to the findall method. i can bring this out by defining an interface for the finder.public interfac
44、e moviefinder list findall();now all of this is very well decoupled, but at some point i have to come up with a concrete class to actually come up with the movies. in this case i put the code for this in the constructor of my lister class.class movielister. private moviefinder finder; public movieli
45、ster() finder = new colondelimitedmoviefinder(movies1.txt); the name of the implementation class comes from the fact that im getting my list from a colon delimited text file. ill spare you the details, after all the point is just that theres some implementation.now if im using this class for just my
46、self, this is all fine and dandy. but what happens when my friends are overwhelmed by a desire for this wonderful functionality and would like a copy of my program? if they also store their movie listings in a colon delimited text file called movies1.txt then everything is wonderful. if they have a
47、different name for their movies file, then its easy to put the name of the file in a properties file. but what if they have a completely different form of storing their movie listing: a sql database, an xml file, a web service, or just another format of text file? in this case we need a different cl
48、ass to grab that data. now because ive defined a moviefinder interface, this wont alter my moviesdirectedby method. but i still need to have some way to get an instance of the right finder implementation into place.figure 1: the dependencies using a simple creation in the lister classfigure 1 shows
49、the dependencies for this situation. the movielister class is dependent on both the moviefinder interface and upon the implementation. we would prefer it if it were only dependent on the interface, but then how do we make an instance to work with?in my book p of eaa, we described this situation as a
50、 plugin. the implementation class for the finder isnt linked into the program at compile time, since i dont know what my friends are going to use. instead we want my lister to work with any implementation, and for that implementation to be plugged in at some later point, out of my hands. the problem
51、 is how can i make that link so that my lister class is ignorant of the implementation class, but can still talk to an instance to do its work.expanding this into a real system, we might have dozens of such services and components. in each case we can abstract our use of these components by talking
52、to them through an interface (and using an adapter if the component isnt designed with an interface in mind). but if we wish to deploy this system in different ways, we need to use plugins to handle the interaction with these services so we can use different implementations in different deployments.
53、so the core problem is how do we assemble these plugins into an application? this is one of the main problems that this new breed of lightweight containers face, and universally they all do it using inversion of control.inversion of controlwhen these containers talk about how they are so useful beca
54、use they implement inversion of control i end up very puzzled. inversion of control is a common characteristic of frameworks, so saying that these lightweight containers are special because they use inversion of control is like saying my car is special because it has wheels.the question, is what asp
55、ect of control are they inverting? when i first ran into inversion of control, it was in the main control of a user interface. early user interfaces were controlled by the application program. you would have a sequence of commands like enter name, enter address; your program would drive the prompts and pick up a response to each one. with graphical (or even screen based) uis the ui framework would contain this main loop and your program instead provided event handlers for the vario
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 10 我們不亂扔 教學(xué)設(shè)計(jì)-2023-2024學(xué)年道德與法治部編版二年級(jí)上冊(cè)統(tǒng)編版
- 第13課 現(xiàn)代戰(zhàn)爭(zhēng)與不同文化的碰撞和交流 教學(xué)設(shè)計(jì)-2023-2024學(xué)年高中歷史統(tǒng)編版(2019)選擇性必修3文化交流與傳播
- 國(guó)外租賃的合同7篇
- 議論文的開頭教學(xué)設(shè)計(jì) 2024-2025學(xué)年統(tǒng)編版高中語(yǔ)文必修上冊(cè)
- 6《光的反射現(xiàn)象》教學(xué)設(shè)計(jì) -2024-2025學(xué)年科學(xué)五年級(jí)上冊(cè)教科版
- 中式餐飲品牌的競(jìng)爭(zhēng)態(tài)勢(shì)
- 第六單元第5課時(shí) 9的乘法口訣和用口訣求商(教學(xué)設(shè)計(jì))二年級(jí)數(shù)學(xué)上冊(cè)同步高效課堂系列(蘇教版)
- 杭州市保齡球館租賃合同
- 2025年度教育研討會(huì)活動(dòng)合同模板
- 2025年高檔裘皮制品項(xiàng)目投資可行性研究分析報(bào)告
- 電梯口包邊施工方案正式
- 部編版六年級(jí)道德與法治下冊(cè)《學(xué)會(huì)反思》教案
- 三年級(jí)道德與法治下冊(cè)我是獨(dú)特的
- 部編版四年級(jí)下冊(cè)語(yǔ)文教案(完整)
- T∕CIS 71001-2021 化工安全儀表系統(tǒng)安全要求規(guī)格書編制導(dǎo)則
- 青年卒中 幻燈
- 典型倒閘操作票
- 第七章 化學(xué)物質(zhì)與酶的相互作用
- 機(jī)械畢業(yè)設(shè)計(jì)論文鋼筋自動(dòng)折彎?rùn)C(jī)的結(jié)構(gòu)設(shè)計(jì)全套圖紙
- 綜采工作面順槽頂板退錨安全技術(shù)措施
- 中國(guó)電機(jī)工程學(xué)報(bào)論文格式模板
評(píng)論
0/150
提交評(píng)論