標籤:
發現一片不錯的文章,內容全是轉載。
一起來看吧。
**********************
架構和類庫等概念的出現都是源於人們對複用的渴望。“不要重複發明輪子”,成了軟體界的一句經典名言。從最初的單個函數原始碼的複用,到物件導向中類的複用(通常以類庫的形式體現),再到基於組件編程中二進位組件(.NET中是以IL程式集形式存在的)的複用,人們複用軟體的抽象層次越來越高。現在,架構複用是抽象層次的又一提升,架構的複用不僅僅是功能的複用,更是設計的複用。
1.1 架構與類庫的區別
我們先來簡單說說什麼是類庫(Class Library)?望文生義,類庫就是一些類的集合,只要我們將一些可以複用的類集中放到一個Library中,我們就可以稱其為一個類庫。類庫中的許多元素(如類、結構、介面、枚舉、委託等)之間可能有一些關聯,但這些關聯通常用於支援一個類概念或介面概念的完整表達。如果我們從一個更高的視角來審視類庫,可以發現類庫中的一個個“完整的概念”之間是無關的或是關係鬆散的。
再來說架構,架構的第一含義是一個骨架,它封裝了某領域內處理流程的控制邏輯,所以我們經常說架構是一個半成品的應用。由於領域的種類是如此眾多,所以架構必須具有針對性,比如,專門用於解決底層通訊的架構,或專門用於醫學領域的架構。架構中也包含了很多元素,但是這些元素之間關係的緊密程度要遠遠大於類庫中元素之間的關係。架構中的所有元素都為了實現一個共同的目標而相互協作。
沒有一個萬能的架構可以應用於所有種類的領域和應用,架構的目標性非常強,它專註於解決某一特定領域的問題,並致力於為這一特定領域提供通用的解決方案。
架構與類庫的區別主要表現在以下幾個方面:
(1)從結構上說,架構內部是高內聚的,而類庫內部則是相對鬆散的。
(2)架構封裝了處理流程的控制邏輯,而類庫幾乎不涉及任何處理流程和控制邏輯。
正是由於架構對處理流程的控制邏輯進行了封裝,才使得架構成為一個應用的骨架。架構中的處理流程和控制邏輯需要經過精心的設計,因為所有使用了該架構的應用程式都會複用該設計。
(3)架構具有IOC(控制反轉)能力,而類庫沒有。
IOC,即俗稱的好萊塢模式(Don’t call us, we will call you)。對於類庫中的元素來說,通常都是由我們的應用來調用它;而架構具有這種能力――在適當的時候調用我們應用中的邏輯。這種能力是通過架構擴充點(或稱為“插槽”)來做到的――具體的應用通過擴充點注入自己的邏輯,而在適當的時候,架構會調用這個擴充點中登入的邏輯。實際上,.NET中的事件(event)發布、預定機制就是IOC的一個代表性例子。
(4)架構專註於特定領域,而類庫卻是更通用的。
架構著力於一個特定領域的解決方案的完整表達,而類庫幾乎不針對任何特定領域。比如,本書中提到的通訊架構只適用於需要在TCP/UDP基礎上直接構建通訊的應用程式,而像Regex這樣的類庫卻可以使用在各種不同的應用中。
(5)架構通常建立在眾多類庫的基礎之上,而類庫一般不會依賴於某架構。
1.2 通用架構與應用程式框架
如果要對架構進行進一步分類,則可以根據架構針對的領域是否具有通用性而將它們分為通用架構(General Framework)和應用程式框架(Application Framework)。通用架構可以在不同類型的應用中使用,而應用程式框架只被使用於某一特定類型的應用中。
比如,ORM架構NHibernate就是一個通用架構,該架構可以用於所有需要解決O/R映射的各種類型的應用中。而某個金融架構則是一個應用程式框架,它僅僅被用於金融類型的應用中。
可以這麼說,通用架構所解決的是所有類型的應用都關心的“普遍”問題,而應用程式框架解決的是某一特定類型的應用關心的問題。所以,如果我們需要將某種類型的應用的核心商務邏輯流程提升到一個架構中,所得到的這個架構就是一個應用程式框架。與通用架構相比,應用程式框架需要瞭解更多目標業務領域內的領域知識。
在實現具體的應用程式時,可以採用一個應用程式框架與多個通用架構相結合的方式,這樣有利於快速、高品質的應用程式開發。比如,某個金融領域的一個應用,可以採用金融架構作為應用程式框架來解決與金融商務邏輯相關的問題,採用Nhibernate解決資料訪問,採用ESFramework解決應用中各分布式系統之間的通訊。
描述了類庫、架構和應用之間的層次關係。
當然,一個應用也可以完全不採用任何架構,而是直接從最基礎的底層API(如.NET Framework)開始構建。對於微型的系統,這種方式或許可行。但對於複雜大型的應用,困難度就可想而知了。
1.3 架構之於應用
當一個應用系統選定了架構之後,我們需要做的就是在架構提供擴充點的地方添加應用的具體邏輯,也就是使用“血”和“肉”來填充這個骨架從而得到一個“有機體”。
由於架構通常都是在實踐中經過反覆使用和檢驗的,所以品質有一定的保證,這使得我們用更少的時間、更少的編碼來實現一個更穩定的系統成為可能。當然,架構也不是“銀彈”,它不能解決軟體複雜性的根本問題,但是我們卻通過它向這個終極的理想目標又邁進了一步。
有一點需要注意,架構使得我們的系統在有所支撐的同時,它也給出了限制。因為通常當我們確定採用了某一個架構之後,我們就必須在這個架構限制的“框框”之內來構建我們的應用。大多數時候,這不是一個問題,但是如果因為架構的限制而嚴重影響了我們系統目標的實現的時候,我們就需要考慮是否應該放棄這個架構,或者換一個其它的同類型的架構。
1.4 架構設計
架構使得我們開發應用的速度更快、品質更高、成本更低,這些好處是不言而喻的。然而,面對萬千變化日趨複雜的軟體需求,設計和實現一個高度靈活可複用的架構又談何容易!
架構源於應用,卻又高於應用。
架構往往是這樣產生的:我們擁有了開發某種類型應用的大量經驗,我們總結這種類型的應用中共性的東西,將其提煉到一個高的層次中,以備複用。這個“高層次”的東西便是架構的原型。隨著我們經驗的不斷積累,架構也會不斷地完善、發展。
架構是一個實踐的產物,而不是在實驗室中理論研究出來的。所以設計一個架構最好的方法就是從一個具體的應用開始,以提供同一類型應用的通用解決方案為目標,不斷地從具體應用中提煉、萃取架構!然後在應用中使用這個架構,並在使用的過程中不斷地修正和完善。
有一點需要特別注意,正如所有的軟體架構設計的要點在於權衡(在這方面有點像藝術),架構的設計也不例外,正如前面提到,架構在為應用提供了一個骨架的同時,也給我們的應用圈定了一個框框,我們只能在這個有限的天地內來發揮。所以,一個好的架構設計應當採用了一個非常恰當的權衡決策,以使架構在為我們應用提供強大支援的同時,而又對我們的應用作更少的限制。權衡,從來就不是一件簡單的事情,但是有很多架構設計的經驗可以供我們參考。
1.4.1 架構設計經驗、原則
(1)架構不要為應用做過多的假設!
關於架構為應用做過多的假設,一個非常具體的現象就是,架構越俎代庖,把本來是應用要做的事情攬過來自己做。這是一種典型的吃力不討好的做法。架構越俎代庖,也許會使得某一個具體應用的開發變得簡單,卻會給其它更多想使用該架構的應用增加了本沒有必要的束縛和負擔。
(2)使用介面,保證架構提供的所有重要實現都是可以被替換的。
架構終究不是應用,所以架構無法考慮所有應用的具體情況,保證所有重要的組件的實現都是可以被替換的,這一點非常重要,它使得應用可以根據當前的實際情況來替換掉架構提供的部分組件的預設實現。使用介面來定義架構中各個組件及組件間的聯絡,將提高架構的可複用性。
(3)架構應當簡潔、一致、且目的地組中。
架構應當簡潔,不要包含那些對架構目標來說無關緊要的東西,保證架構中的每個組件的存在都是為了支援架構目標的實現。包含過多無謂的元素(類、介面、枚舉等),會使架構變得難以理解,嘗試將這些對於架構核心目標不太重要的元素轉移到類庫中,可以使得架構更清晰、目標更集中。
(4)提供一個常用的骨架,但是不要固定骨架的結構,使骨架也是可以組裝的。
比如說,如果是針對某種業務處理的架構,那麼架構不應該只提供一套不可變更的業務處理流程,而是應該將處理流程“單步”化,使得各個步驟是可以重新組裝的,如此一來,應用便可以根據實際情況來改變架構預設的處理流程。這種架構的可定製化能力可以極大地提高架構的可複用性。
(5)不斷地重構架構。
如果說設計和實現一個高品質的架構有什麼秘訣?答案只有一個,重構、不斷地重構。重構架構的實現代碼、甚至重構架構的設計。重構的驅動力源於幾個方面,比如對要解決的本質問題有了更清晰準備的認識,在使用架構的時候發現某些組件職責不明確、難以使用,架構的階層不夠清晰等。
1.4.2 如何稱得上一個優秀的架構?
一個優秀架構的最主要的特點是:簡單。這種簡單性不是輕而易舉就可以獲得的,正如優秀的架構不是一蹴而就的,達到這種簡單性需要對架構不斷地抽絲、不斷地提煉和完善。簡單的真正原因在於它抓住了要解決的問題的本質。一個優秀的架構通常都具有如下特點:
(1)清晰的、簡潔的、一致的。
“清晰”指的是架構的結構是清晰的、架構的層次是清晰明朗的、架構中各個類和組件的職責是清晰明確的。
“簡潔”指的是架構中沒有無關緊要多餘的元素,而且各個類和組件的職責目標是非常集中的,這正是“高內聚、低耦合”設計原則的體現。
“一致”通常會帶來這樣的好處,架構的使用者在熟悉了架構的一部分後,會非常容易地理解架構的另一部分。“一致”通常體現在命名的規則一致、命名的含義一致、組件的裝配方式和使用方式一致等。
(2)便於使用的
只有便於使用的架構才會走得更遠。
正是因為便於使用,架構使用者們才有可能試用這個架構,在試用滿意後才有可能決定採用這個架構。一個架構功能即使再強大,如果難以使用,那麼架構使用者們很可能根本就不會有試用這個架構的念頭。
架構的生命力源於架構一直在不斷地完善和發展,如果沒有人使用這個架構,這個架構便沒有了發展和完善的源動力。正如友好的使用者介面是優秀應用程式不可或缺的重要部分,便於使用也是優秀架構的一個重要特性。
(3)高度可擴充的、靈活的
架構通過高度可擴充性來應對應用程式的萬千變化。
沒有任何一個架構可以預料所有應用的需求,萬能的架構是不存在的。企圖設計、實現一個萬能架構的想法是荒誕的。架構必須具有“以不變應萬變”的能力,架構可以通過為應用預留恰當的、足夠的擴充點來做到這一點。
架構的靈活體現在架構可以根據不同的應用進行不同的組裝和配置,就像架構是專門為當前的應用所訂製的一樣。
(4)輕量的
“輕量”,說的通俗點,就是只為自己需要使用的服務付費,而不需要為自己不需要的服務買單。一個重量級的架構有一個很明顯的特徵就是,如果你需要一套完整的套餐服務,那是沒有問題的,架構可以很好的滿足你;但是,如果你只需要這份套餐中的一小塊點心,對不起,架構仍然會強加一個完整的套餐給你,你必須付一整份套餐的費用。
優秀的架構應當支援使用者“按需所取”的原則,架構使用者可以隨意“點菜”進行組裝來滿足自己的需求。
(5)弱侵入性的
所謂“弱侵入性”,採用了架構的應用程式可以儘可能的以普通的方式來編寫應用邏輯,而不必為了適應架構不得不使用一些特殊的手法。
這可能有點難以理解,我們可以舉個例子來簡單說明。在.NET中,實現AOP(面向方面編程)機制的兩種主要方式是使用Proxy和動態代理。使用Proxy實現的AOP架構通常要求那些需要使用AOP截獲功能的類必須繼承自ContexBoundObject;而採用動態代理實現的AOP架構則沒有任何如此侵入性的要求,我們仍可以以最普通的方式來編寫應用邏輯類,這類架構會在運行時根據配置動態地產生目標對象的代理對象來實現AOP截獲。所以我們可以說,採用動態代理方式實現的AOP架構相比採用Proxy實現的AOP架構,具有更弱的侵入性。
弱侵入性意味著架構對應用邏輯的幹擾更少,由於應用邏輯類都是普通的類,這非常方便應用邏輯在另外一個程式中複用,而另外的程式可能採用了一個完全不同的架構。
架構與類庫的區別(轉載)