轉(zhuǎn)帖|行業(yè)資訊|編輯:龔雪|2017-02-07 11:43:52.000|閱讀 965 次
概述:你一定曾為這些“高深術(shù)語”感到過困擾。也許時至今日,你仍對它們一知半解。現(xiàn)在奉上一份深入淺出的講解,為各位程序員答疑解惑。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
1.內(nèi)聚
內(nèi)聚的概念是Constantine、Yourdon、Stevens等人提出的。按他們的觀點,把內(nèi)聚按緊密程度從低到高排列次序為偶然內(nèi)聚、邏輯內(nèi)聚、時間內(nèi)聚、過程內(nèi)聚、通信內(nèi)聚、信息內(nèi)聚、功能內(nèi)聚。但是緊密程度的增長是非線性的。偶然內(nèi)聚和邏輯內(nèi)聚的模塊聯(lián)系松散,后面幾種內(nèi)聚相差不多,功能內(nèi)聚一個功能、獨立性強(qiáng)、內(nèi)部結(jié)構(gòu)緊密,是最理想的內(nèi)聚。經(jīng)典理論告訴我們,程序的兩大要素:一個是數(shù)據(jù)(data),一個是操作(opration)。而 PASCAL之父Nicklaus Wirth則進(jìn)一步提出了“程序 = 數(shù)據(jù)結(jié)構(gòu) + 算法”的著名公式。雖然提法上有所差異,但是其根本內(nèi)涵卻是一致的,微妙的差別在于,“數(shù)據(jù) + 操作”是微觀的視域,“數(shù)據(jù)結(jié)構(gòu) + 算法”則是中觀的視域。而在宏觀的視域下,我認(rèn)為“程序 = 對象 + 消息”。對象是什么?對象就是保管好自己的東西,做好自己的事情的程序模塊——這就是內(nèi)聚!傳統(tǒng)的面向過程編程方法由于割裂了數(shù)據(jù)結(jié)構(gòu)和算法,使得軟件的內(nèi)聚性普遍低迷,曾一度引發(fā)了軟件危機(jī)。試想,大家都自己的東西不好好保管,自己的事情也不好好做,不引發(fā)危機(jī)才怪呢!當(dāng)然,對象的內(nèi)聚只是內(nèi)聚的一個層次,在不同的尺度下其實都有內(nèi)聚的要求,比如方法也要講內(nèi)聚,架構(gòu)也要講內(nèi)聚。
2. 依賴·耦合
依賴(Dependency)關(guān)系是類與類之間的聯(lián)接。依賴關(guān)系表示一個類依賴于另一個類的定義。例如,一個人(Person)可以買車(car)和房子(House),Person類依賴于Car類和House類的定義,因為Person類引用了Car和House。與關(guān)聯(lián)不同的是,Person類里并沒有Car和House類型的屬性,Car和House的實例是以參量的方式傳入到buy()方法中去的。一般而言,依賴關(guān)系在Java語言中體現(xiàn)為局域變量、方法的形參,或者對靜態(tài)方法的調(diào)用。
只要兩個對象之間存在一方依賴一方的關(guān)系,那么我們就稱這兩個對象之間存在耦合。 比如媽媽和baby,媽媽要隨時關(guān)注baby的睡、醒、困、哭、尿等等狀態(tài),baby則要仰賴媽媽的喂奶、哄睡、換紙尿褲等行為,從程序的意義上說,二者互相依賴,因此也存在耦合。首先要說,耦合是必要的。
3. 耦合度·解耦和
耦合的程度就是耦合度,也就是雙方依賴的程度。上文所說的媽媽和baby就是強(qiáng)耦合。而你跟快遞小哥之間則是弱耦合。一般來說耦合度過高并不是一件好事。就拿作為IT精英的你來說吧,上級隨時敦促你的工作進(jìn)度,新手頻繁地需要你指導(dǎo)問題,隔三差五還需要參加酒局飯局,然后還要天天看領(lǐng)導(dǎo)的臉色、關(guān)注老婆的心情,然后你還要關(guān)注代碼中的bug 、bug、bug,和需求的變化、變化、變化,都夠焦頭爛額了,還猝不及防的要關(guān)注眼睛、頸椎、前列腺和頭發(fā)的狀態(tài),然后你再炒個股,這些加起來大概就是個強(qiáng)耦合了。從某種意義上來說,耦合天生就與自由為敵,無論是其他對象依賴于你,還是你依賴其他對象。比如有人嗜煙、酗酒,你有多依賴它們就有多不自由;比如有人家里生了七八個娃,還有年邁的父母、岳父母,他們有多依賴你,你就有多不自由。所以老子這樣講:“五音令人耳聾,五色令人目盲,馳騁狩獵令人心發(fā)狂,難得之貨令人行妨。”盧梭也是不無悲涼的說“人生而自由,卻又無往而不在枷鎖中”。因此,要想自由,就必須要降低耦合,而這個過程就叫做解耦和。
4. 依賴倒置(Dependence Inversion Principle)
解耦和最重要的原則就是依賴倒置原則:
高層模塊不應(yīng)該依賴底層模塊,他們都應(yīng)該依賴抽象。抽象不應(yīng)該依賴于細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴于抽象。
《資本論》中都曾闡釋依賴倒轉(zhuǎn)原則——在商品經(jīng)濟(jì)的萌芽時期,出現(xiàn)了物物交換。假設(shè)你要買一個IPhone,賣IPhone的老板讓你拿一頭豬跟他換,可是你并沒有養(yǎng)豬,你只會編程。所以你找到一位養(yǎng)豬戶,說給他做一個養(yǎng)豬的APP來換他一頭豬,他說換豬可以,但是得用一條金項鏈來換——所以這里就出現(xiàn)了一連串的對象依賴,從而造成了嚴(yán)重的耦合災(zāi)難。解決這個問題的最好的辦法就是,買賣雙發(fā)都依賴于抽象——也就是貨幣——來進(jìn)行交換,這樣一來耦合度就大為降低了。
再舉一個編程中的依賴倒置的例子。我們知道,在通信中,消息的收發(fā)和消息的處理往往密不可分。就一般的通信框架而言,消息的收發(fā)通常是已經(jīng)實現(xiàn)了的,而消息的處理則是需要用戶來自定義完成的。先看一個正向依賴的例子:輕量級通信引擎StriveEngine。tcpServerEngine是StriveEngine.dll提供通信引擎,它發(fā)布有一個MessageReceived事件。假設(shè)我定義了一個CustomizeHandler類來用于消息處理,那么CustomizeHandler的內(nèi)部需要預(yù)定tcpServerEngine的MessageReceived事件,因此customizeHandler依賴于tcpServerEngine,這就是一個普通的依賴關(guān)系,也就是高層模塊依賴于低層模塊。
而ESFramework通信框架則應(yīng)用了依賴倒轉(zhuǎn)原則。ESFramework定義了一個IcustomizeHandler接口,用戶在進(jìn)行消息處理時,實現(xiàn)該接口,然后將其注入到rapidPassiveEngine客戶端通信引擎之中。
class CustomizeHandler: ICustomizeHandler { public void HandleInformation(string sourceUserID, int informationType, byte[] info) { •••••• } public byte[] HandleQuery(string sourceUserID, int informationType, byte[] info) { •••••• } } IRapidPassiveEngine rapidPassiveEngine = ESPlus.Rapid.RapidEngineFactory.CreatePassiveEngine(); CustomizeHandler customizeHandler = new CustomizeHandler(); rapidPassiveEngine.Initialize("ID", "passWord", "127.0.0.1", 9000, customizeHandler);
很明顯,相比于上一個例子,這里的依賴關(guān)系變成了rapidPassiveEngine依賴于customizeHandler,也就是說依賴關(guān)系倒置了過來,上層模塊不再依賴于底層模塊,而是它們共同依賴于抽象。rapidPassiveEngine依賴的是IcustomizeHandler接口類型的參數(shù),customizeHandler同樣是以實現(xiàn)的接口的方式依賴于IcustomizeHandler——這就是一個依賴倒置的典范。
5. 控制反轉(zhuǎn)(Inversion of Control)
控制反轉(zhuǎn)跟依賴倒置是如出一轍的兩個概念,當(dāng)存在依賴倒置的時候往往也存在著控制反轉(zhuǎn)。但是控制反轉(zhuǎn)也有自己的獨特內(nèi)涵。
首先我們要區(qū)分兩個角色,server 跟 Client,也就是服務(wù)方和客戶方。提供服務(wù)端的一方稱為服務(wù)方,請求服務(wù)的一方稱為客戶方。我們最熟悉的例子就是分布式應(yīng)用的C/S架構(gòu),服務(wù)端和客戶端。其實除此之外,C/S關(guān)系處處可見。比如在TCP/IP協(xié)議棧中,我們知道,每層協(xié)議為上一層提供服務(wù),那么這里就是一個C/S關(guān)系。當(dāng)我們使用開發(fā)框架時,開發(fā)框架就是作為服務(wù)方,而我們自己編寫的業(yè)務(wù)應(yīng)用就是客戶方。當(dāng)Client調(diào)用server時,這個叫做一般的控制;而當(dāng)server調(diào)用Client時,就是我們所說的控制反轉(zhuǎn),同時我們也將這個調(diào)用稱為“回調(diào)”。控制反轉(zhuǎn)跟依賴倒置都是一種編程思想,依賴倒置著眼于調(diào)用的形式,而控制反轉(zhuǎn)則著眼于程序流程的控制權(quán)。一般來說,程序的控制權(quán)屬于Client,而一旦控制權(quán)交到server,就叫控制反轉(zhuǎn)。比如你去下館子,你是Client餐館是server。你點菜,餐館負(fù)責(zé)做菜,程序流程的控制權(quán)屬于Client;而如果你去自助餐廳,程序流程的控制權(quán)就轉(zhuǎn)到server了,也就是控制反轉(zhuǎn)。
控制反轉(zhuǎn)的思想體現(xiàn)在諸多領(lǐng)域。比如事件的發(fā)布/ 訂閱就是一種控制反轉(zhuǎn),GOF設(shè)計模式中也多處體現(xiàn)了控制反轉(zhuǎn),比如典型的模板方法模式等。而開發(fā)框架則是控制反轉(zhuǎn)思想應(yīng)用的集中體現(xiàn)。比如之前所舉的ESFramework通信框架的例子,通信引擎回調(diào)用戶自定義的消息處理器,這就是一個控制反轉(zhuǎn)。以及ESFramework回調(diào)用戶自定義的群組關(guān)系和好友關(guān)系,回調(diào)用戶自定義的用戶管理器以管理在線用戶相關(guān)狀態(tài),回調(diào)用戶自定義的登陸驗證處理,等等不一而足。再比如與ESFramework一脈相承的輕量級通信引擎StriveEngine,通過回調(diào)用戶自定義的通信協(xié)議來實現(xiàn)更加靈活的通信。
6. 依賴注入(Dependency Injection)
依賴注入與依賴倒置、控制反轉(zhuǎn)的關(guān)系仍舊是一本萬殊。依賴注入,就其廣義而言,即是通過“注入”的方式,來獲得依賴。我們知道,A對象依賴于B對象,等價于A對象內(nèi)部存在對B對象的“調(diào)用”,而前提是A對象內(nèi)部拿到了B對象的引用。B對象的引用的來源無非有以下幾種:A對象內(nèi)部創(chuàng)建(無論是作為字段還是作為臨時變量)、構(gòu)造器注入、屬性注入、方法注入。后面三種方式統(tǒng)稱為“依賴注入”,而第一種方式我也生造了一個名詞,稱為“依賴內(nèi)生”,二者根本的差異即在于,我所依賴的對象的創(chuàng)建工作是否由我自己來完成。當(dāng)然,這個是廣義的依賴注入的概念,而我們一般不會這樣來使用。我們通常使用的,是依賴注入的狹義的概念。不過,直接陳述其定義可能會過于詰屈聱牙,我們還是從具體的例子來看。
比如OMCS網(wǎng)絡(luò)語音視頻框架,它實現(xiàn)了多媒體設(shè)備(麥克風(fēng)、攝像頭、桌面、電子白板)的采集、編碼、網(wǎng)絡(luò)傳送、解碼、播放(或顯示)等相關(guān)的一整套流程,可以快速地開發(fā)出視頻聊天系統(tǒng)、視頻會議系統(tǒng)、遠(yuǎn)程醫(yī)療系統(tǒng)、遠(yuǎn)程教育系統(tǒng)、網(wǎng)絡(luò)監(jiān)控系統(tǒng)等等基于網(wǎng)絡(luò)多媒體的應(yīng)用系統(tǒng)。然而,OMCS直接支持的是通用的語音視頻設(shè)備,而在某些系統(tǒng)中,需要使用網(wǎng)絡(luò)攝像頭或者特殊的視頻采集卡作為視頻源,或者其它的聲音采集設(shè)備作為音頻源,OMCS則提供了擴(kuò)展接口——用戶自己實現(xiàn)這個擴(kuò)展的接口,然后以“依賴注入”的方式將對象實例注入到OMCS中,從而完成對音、視頻設(shè)備的擴(kuò)展。擴(kuò)展方法詳情參考
“依賴注入”常常用于擴(kuò)展,尤其是在開發(fā)框架的設(shè)計中。從某種意義上來說,任何開發(fā)框架,天生都是不完整的應(yīng)用程序。因此,一個優(yōu)秀的開發(fā)框架,不僅要讓開發(fā)者能夠重用這些久經(jīng)考驗的的卓越的解決方案,也要讓開發(fā)者能夠向框架中插入自定義的業(yè)務(wù)邏輯,從而靈活自由地適應(yīng)特定的業(yè)務(wù)場景的需要——也就是說要具備良好的可擴(kuò)展性。比如上面提到的OMCS網(wǎng)絡(luò)語音視頻框架可應(yīng)用于音、視頻聊天系統(tǒng)、視頻會議系統(tǒng)、遠(yuǎn)程醫(yī)療系統(tǒng)、遠(yuǎn)程教育系統(tǒng)、網(wǎng)絡(luò)監(jiān)控系統(tǒng)等等基于網(wǎng)絡(luò)多媒體的應(yīng)用系統(tǒng);以及ESFramework通信框架能夠應(yīng)用于即時通訊系統(tǒng),大型多人在線游戲、在線網(wǎng)頁游戲、文件傳送系統(tǒng)、數(shù)據(jù)采集系統(tǒng)、分布式OA系統(tǒng)等任何需要分布式通信的軟件系統(tǒng)中——這種良好的擴(kuò)展性都與“依賴注入”的使用密不可分!
7. 面向接口編程
談到最后,“面向接口編程”已經(jīng)是呼之欲出。無論是依賴倒置、控制反轉(zhuǎn)、還是依賴注入,都已經(jīng)蘊(yùn)含著“面向接口編程”的思想。面向接口,就意味著面向抽象。作為哲學(xué)范疇而言,規(guī)定性少稱為抽象,規(guī)定性多稱為具體。而接口,就是程序中的一種典型的“抽象”的形式。面向抽象,就意味著面向事物的本質(zhì)規(guī)定性,擺脫感性雜多的牽絆,從而把握住“必然”——而這本身就意味著自由,因為自由就是對必然的認(rèn)識。
也許以上的這段論述太過“哲學(xué)”,但是“一本之理”與“萬殊之理”本身就“體用不二”——總結(jié)來看,依賴倒置、控制反轉(zhuǎn)、依賴注入都圍繞著“解耦和”的問題,而同時自始至終又都是“面向接口編程”的方法——因此,“面向接口編程”天生就是“解耦和”的好辦法。由此也印證了從“抽象”到“自由”的這一段范疇的辯證衍化。
“面向?qū)ο?rdquo;與“面向接口”并非兩種不同的方法學(xué),“面向接口”其實是“面向?qū)ο?rdquo;的內(nèi)在要求,是其一部分內(nèi)涵的集中表述。我們對于理想軟件的期待常被概括為“高內(nèi)聚,低耦合”,這也是整個現(xiàn)代軟件開發(fā)方法學(xué)所追求的目標(biāo)。面向?qū)ο蠓椒▽W(xué)作為現(xiàn)代軟件開發(fā)方法學(xué)的代表,本身就蘊(yùn)含著“高內(nèi)聚,低耦合”的思想精髓,從這個意義上來說,“面向?qū)ο?rdquo;這個表述更加側(cè)重于“高內(nèi)聚”,“面向接口”的表述則更加側(cè)重于“低耦合”——不過是同一事物的不同側(cè)面罷了。(稿源:)
更多行業(yè)資訊,更新鮮的技術(shù)動態(tài),盡在。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn