組件(
Component
)應(yīng)該是在現(xiàn)代軟件工程中,除了對(duì)象(
Object
)之外的第二個(gè)炙手可熱的詞了。然而,什么是一個(gè)組件?是一個(gè)某些邏輯集合的實(shí)現(xiàn)?還是一個(gè)承載這些實(shí)現(xiàn)的物理實(shí)體(例如
DLL
)?還是一個(gè)包括了邏輯實(shí)現(xiàn)、物理載體以及相關(guān)的類型信息、安全策略和版本信息的一個(gè)大而全的集合?也許你會(huì)說任何一種解釋都是正確的。的確,不同的環(huán)境中,
Component
有著不同的含義,但是,在
.NET
中,我們就可以把一個(gè)
.NET Class
當(dāng)作一個(gè)
Component
。
既然類和組件有著這么多類似的地方,那么傳統(tǒng)的面向?qū)ο缶幊毯兔嫦蚪M件編程有什么區(qū)別呢?簡單的說,面向?qū)ο箨P(guān)注的是組合在一個(gè)二進(jìn)制可執(zhí)行文件中的各個(gè)類的關(guān)系,而面向組件的編程關(guān)注的是在彼此獨(dú)立的基礎(chǔ)上模塊之間的交互性,這種交互性使得你并不需要熟悉它們內(nèi)部的工作原理。
分而治之 VS 集大成
這兩種方法最基本的不同在于它們對(duì)最終的應(yīng)用程序的觀點(diǎn)。在傳統(tǒng)的面向?qū)ο缶幊讨校M管你可以精心的把所有的商業(yè)邏輯分布在不同的類中,一旦這些類被編譯,它們就被固化成了一個(gè)巨大的二進(jìn)制代碼。所有的類共享同一個(gè)物理單元(通常是一個(gè)可執(zhí)行文件)、被操作系統(tǒng)認(rèn)為是同一個(gè)進(jìn)程,使用同一個(gè)地址空間以及共享相同的安全策略等等。如果多個(gè)開發(fā)者在同一份代碼上進(jìn)行開發(fā),他們甚至還要共享源文件。在這種情況下,修改一個(gè)類可能會(huì)讓整個(gè)項(xiàng)目被重新鏈接,并重新進(jìn)行必要的測(cè)試,更嚴(yán)重的,還有可能要修改其他的類。但是,在面向組件開發(fā)中,應(yīng)用程序是由一系列可以互相交互的二進(jìn)制模塊組合而成的。
一個(gè)具體的二進(jìn)制組件可能并不能完成什么工作。有些組件是為了提供一些常規(guī)服務(wù)而編寫的,例如通信的封裝或者文件訪問組件。也有一些是為了某些特定應(yīng)用而專門開發(fā)的。一個(gè)應(yīng)用程序的設(shè)計(jì)者可以通過把這些不同的組件提供的功能粘合在一起來實(shí)現(xiàn)他們需要的商業(yè)邏輯。很多面向組件的技術(shù)——例如:
COM
、
J2EE
、
CORBA
和
.NET
都為二進(jìn)制組件提供了的無縫鏈接的機(jī)制。而唯一的不同就是你需要在組件通信上花費(fèi)的力氣。
把一個(gè)二進(jìn)制應(yīng)用程序分解成不同的二進(jìn)制組件的動(dòng)機(jī)和把不同的類放到不同的文件中是類似的。后者使得不同的類的開發(fā)人員可以彼此獨(dú)立的工作,盡管即時(shí)修改了一個(gè)類也要重新鏈接整個(gè)應(yīng)用程序,但是你只需要重新編譯被修改的部分就可以了。
但是,面向組件的開發(fā)還是和簡單軟件項(xiàng)目的管理更復(fù)雜一些。因?yàn)橐粋€(gè)面向組件的應(yīng)用程序是一個(gè)二進(jìn)制代碼塊的集合,你可以把組件當(dāng)作是
LEGO
的積木塊一樣,隨心所欲的拆裝它們。如果你需要修改一個(gè)組件的實(shí)現(xiàn),只需要修改那個(gè)組件就可以了,而組件的客戶機(jī)不需要重新編譯也不需要重新開發(fā)。對(duì)于那些不常用到的組件,組件甚至可以在一個(gè)程序運(yùn)行的時(shí)候被更新。這些改進(jìn)和增強(qiáng)使得組件可以立即進(jìn)行更新,而所有該組件的客戶都將立即受益。無論是在同一臺(tái)機(jī)器上還是通過網(wǎng)絡(luò)遠(yuǎn)程訪問。
面向組件的應(yīng)用程序也更易于擴(kuò)展。當(dāng)你需要實(shí)現(xiàn)新的需求的時(shí)候,你可以提供一個(gè)新的組件,而不去影響那些和新需求無關(guān)的組件。這些特點(diǎn)使得面向組件的開發(fā)降低了大型軟件項(xiàng)目長期維護(hù)的成本,這是一個(gè)最實(shí)際的商業(yè)問題,也正是如此,組件技術(shù)才如此迅速的被接受。
面向組件的應(yīng)用程序通常可以更快的響應(yīng)市場(chǎng),因?yàn)槟憧梢杂泻艽蟮倪x擇空間,不僅僅是自己開發(fā)的組件,還可以從第三方廠商來購買某些組件,從而避免了重復(fù)制造輪子。這里,
VB
就是一個(gè)很好的例子,豐富的
ActiveX
控件使得很多人在快速開發(fā)中得到了享受。
接口還是繼承
面向?qū)ο蠛兔嫦蚪M件另一個(gè)重要的不同在于這兩種技術(shù)在繼承和重用模型上的側(cè)重點(diǎn)不同。
在面向?qū)ο蟮姆治龊驮O(shè)計(jì)中,應(yīng)用程序通常被分解成復(fù)雜的類繼承結(jié)構(gòu)。類的設(shè)計(jì)和要解決的商業(yè)問題緊密結(jié)合。你可以從已有基類繼承并特化其行為來實(shí)現(xiàn)代碼重用。問題在于,這是一種很糟糕的重用的方法。當(dāng)你從一個(gè)基類派生一個(gè)子類的時(shí)候,你必須對(duì)基類的實(shí)現(xiàn)有透徹的理解才可能保證不出問題。例如:修改一個(gè)成員變量會(huì)不會(huì)帶來副作用?這會(huì)對(duì)基類中的代碼有什么影響?重載基類的方法會(huì)不會(huì)破壞那些想使用基類版本的客戶的行為?等等。
這種形式的重用被稱為白盒重用(White-box reuse),因?yàn)楫?dāng)你重用的時(shí)候你就需要去了解基類實(shí)現(xiàn)的細(xì)節(jié)。顯然。白盒重用在可擴(kuò)展性較高的大型應(yīng)用中并不經(jīng)濟(jì),也很難得到第三方Framework廠商的支持。
面向組件的開發(fā)采用了黑盒重用(Black-box reuse)的方法,它可以讓你對(duì)組件內(nèi)部全然不知的情況下來使用組件公開的接口。這樣,你就可以遠(yuǎn)離那些復(fù)雜的繼承關(guān)系。而面向組件的開發(fā)者也可以把更多的精力放在制定組件和客戶的溝通的接口上了。
最后,面向?qū)ο缶幊烫峁┝擞邢薜墓ぞ吆驮O(shè)計(jì)模式來處理和應(yīng)用程序運(yùn)行時(shí)相關(guān)的問題,例如多線程、并發(fā)管理、安全、分布式應(yīng)用和版本控制等。面向?qū)ο蟮拈_發(fā)者當(dāng)面對(duì)這些“公共需求”的時(shí)候,或多或少的需要自己來解決問題。但是面向組件的開發(fā)方式卻使你在這方面要靈活的多。