|
在對(duì)NLayerApp實(shí)際項(xiàng)目進(jìn)行討論之前,讓我們首先學(xué)習(xí)一下(或者應(yīng)該說重溫一下)分層/多層架構(gòu)與應(yīng)用系統(tǒng)設(shè)計(jì)原則。很多朋友會(huì)認(rèn)為這些都是老掉牙的內(nèi)容,只要是軟件從業(yè)人員,都會(huì)對(duì)這些內(nèi)容非常熟悉。然而,果真如此嗎?我在這里整理這部分內(nèi)容,一方面是為介紹NLayerApp打下基礎(chǔ),而另一方面,則是希望借此機(jī)會(huì)將這些理論性的東西做個(gè)歸納,也希望讀者朋友能夠認(rèn)真閱讀,畢竟溫故知新嘛。
需要說明的是,從本章節(jié)開始,大多數(shù)理論性的東西都源自Microsoft Spain團(tuán)隊(duì)針對(duì)NLayerApp所編寫的《Architecture Guide Book》,事實(shí)上這本Guideline的英文版至今也還沒有完成,我會(huì)從中抽出部分章節(jié)做些翻譯和歸納,有興趣的朋友請(qǐng)直接上microsoftnalyerapp.codeplex.com站點(diǎn)上下載英文版閱讀。
Layers與Tiers
對(duì)Layers與Tiers這兩個(gè)單詞進(jìn)行區(qū)分是非常重要的。從中文翻譯看,兩者都是層的意思,因此我們往往會(huì)將這兩個(gè)概念弄混。Layer一詞更多的是表示對(duì)系統(tǒng)組件或功能的邏輯區(qū)分,它并沒有包含將組件分布到不同的區(qū)域、不同的服務(wù)器上的意思。而Tier則是表示系統(tǒng)組件和功能在服務(wù)器、網(wǎng)絡(luò)環(huán)境以及遠(yuǎn)程位置的物理部署。盡管這兩個(gè)概念同時(shí)使用者非常相近的一些術(shù)語(yǔ),比如展示、服務(wù)、業(yè)務(wù)和數(shù)據(jù)等,但我們必須了解它們之間的差別。下面這幅圖表明了多層(N-Layer)邏輯架構(gòu)與三層(3-Tier)物理結(jié)構(gòu)之間的差異:
需要注意的是,對(duì)于具有一定復(fù)雜度的應(yīng)用程序而言,采用多層(N-Layer)邏輯架構(gòu)的實(shí)現(xiàn)方式是非常必要的,這會(huì)降低系統(tǒng)的復(fù)雜度,并在設(shè)計(jì)、開發(fā)、測(cè)試、部署及維護(hù)等各個(gè)環(huán)節(jié)為應(yīng)用系統(tǒng)帶來高可用性、高延展性等正面效應(yīng)。然而,并非所有的應(yīng)用程序必須以三層(3-Tier)/多層(N-Tier)物理結(jié)構(gòu)進(jìn)行部署,我們可以將多個(gè)邏輯層部署在同一臺(tái)機(jī)器上,也可以根據(jù)需求,將這些邏輯層部署在網(wǎng)絡(luò)中的不同機(jī)器上。
邏輯分層(Layer)的設(shè)計(jì)
在討論DDD的分層之前,先讓我們看看傳統(tǒng)的分層方式。就像上文所述,我們應(yīng)該根據(jù)項(xiàng)目的實(shí)際需求,將組件/功能模塊合理地劃分到邏輯層中。同一層中的組件,應(yīng)該是高內(nèi)聚的,并具有相同的抽象層次。層與層之間應(yīng)該低耦合。對(duì)于以分層設(shè)計(jì)的應(yīng)用程序而言,最關(guān)鍵的問題就是如何處理層與層之間的依賴關(guān)系。考察傳統(tǒng)的多層架構(gòu)應(yīng)用,處于某層的組件,只能對(duì)同層或下層的其它組件進(jìn)行訪問,這樣做可以有效地降低層與層之間的依賴關(guān)系。通常會(huì)有兩種分層設(shè)計(jì):嚴(yán)格分層與靈活分層
- 嚴(yán)格分層迫使組件只能訪問同層的其它組件,或者只能訪問直接下層的其它組件,于是,第N層的組件只能訪問第N或N-1層的組件,而第N-1層的組件只能訪問第N-1或N-2層的組件,以此類推
- 靈活分層允許組件訪問同層的其它組件,以及所有下層的其它組件,于是,第N層的組件可以訪問第N或N-1、N-2…層的組件
使用靈活分層的架構(gòu)可以提高系統(tǒng)性能,因?yàn)檫@樣的結(jié)構(gòu)無需引入過多的請(qǐng)求/反饋的傳遞操作,因?yàn)橐粋€(gè)層可以直接訪問位于其下的任何層;而嚴(yán)格分層卻降低了層與層之間的耦合性,對(duì)低層的修改不會(huì)對(duì)整個(gè)系統(tǒng)造成廣泛的影響。根據(jù)Eric Evans在其《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)-軟件核心復(fù)雜性應(yīng)對(duì)之道》一書中的描述,DDD的分層選用的是靈活分層模式。
讓我們?cè)侔延懻摰牧6燃?xì)化,來看看層中的組件與組件之間的關(guān)系。事實(shí)上,在很多復(fù)雜的應(yīng)用中,位于同一層的組件與組件雖然具有相同的抽象層次,它們也不一定是高內(nèi)聚的。因此,我們可以引入模塊(Module)的概念,將同一層中高內(nèi)聚的組件放在同一個(gè)模塊中,于是,每個(gè)層又會(huì)由一個(gè)或多個(gè)高內(nèi)聚的子系統(tǒng)(模塊)所組成,如下UML組件圖所示:
使用分層架構(gòu),有如下幾點(diǎn)好處:
- 提高系統(tǒng)的可測(cè)試性
- 對(duì)解決方案的維護(hù)和管理變得更加簡(jiǎn)單。層內(nèi)高內(nèi)聚、層間低耦合的結(jié)構(gòu),使得系統(tǒng)實(shí)現(xiàn)與分層組織方式變得非常靈活方便
- 其它外部應(yīng)用程序能夠非常方便地使用不同的層所提供的特定功能
- 當(dāng)系統(tǒng)以層的方式進(jìn)行組織時(shí),分布式開發(fā)也變得非常簡(jiǎn)單易行
- 在某些情況下,分層系統(tǒng)的物理部署方式能夠給系統(tǒng)帶來延展性,當(dāng)然,應(yīng)該有效地評(píng)估具體的實(shí)踐方式,因?yàn)檫@種做法有可能損傷系統(tǒng)性能
應(yīng)用系統(tǒng)基本設(shè)計(jì)原則 - SOLID
應(yīng)用系統(tǒng)的設(shè)計(jì)應(yīng)該遵循一些基本的設(shè)計(jì)原則,這能幫助你有效地創(chuàng)建一個(gè)低成本、高可用、高可擴(kuò)展的應(yīng)用程序。在這里,我們引入一個(gè)SOLID設(shè)計(jì)原則,SOLID由如下幾點(diǎn)構(gòu)成:
- Single Responsibility Principle(單一職責(zé)原則)
- Open Close Principle(開-閉原則)
- Liskov Substitution Principle(里氏替換原則)
- Interface Segregation Principle(接口分離原則)
- Dependency Inversion Principle(依賴反轉(zhuǎn)原則)
下面簡(jiǎn)要介紹一下這幾個(gè)原則。
- 單一職責(zé)原則:每個(gè)類應(yīng)該只有一個(gè)獨(dú)一無二的職責(zé),或者說每個(gè)類只能有一個(gè)主要功能,由此派生出一個(gè)結(jié)論:每個(gè)類應(yīng)該盡可能少地依賴于其它類
- 開-閉原則:每個(gè)類,應(yīng)該對(duì)擴(kuò)展進(jìn)行開放,而對(duì)修改進(jìn)行封閉,也就是支持?jǐn)U展,而不是支持修改:類中的方法可以通過繼承關(guān)系進(jìn)行擴(kuò)展,而不會(huì)改變類本身的代碼
- 里氏替換原則:子類可以被基類型(基類或者接口)替換。應(yīng)用程序依賴抽象運(yùn)行,其行為不會(huì)因?yàn)榫唧w實(shí)現(xiàn)的改變而更改,應(yīng)用程序應(yīng)該依賴于抽象(基類或者接口),而不是具體實(shí)現(xiàn)。接下來將要討論到的依賴注入(Dependency Injection)就與這條原則有關(guān)
- 接口分離原則:接口的職責(zé)也應(yīng)該是單一的,接口中應(yīng)該包含哪些方法,需要進(jìn)行嚴(yán)格的評(píng)估,如果其中某些方法的職責(zé)與接口的本身定義不相符合,則應(yīng)該將其分離到其它接口中。類需要根據(jù)其調(diào)用者所需要的不同接口類型,來暴露不同的接口
- 依賴反轉(zhuǎn)原則:抽象不能依賴于具體,而具體則應(yīng)該依賴于抽象。類之間的直接依賴應(yīng)該用抽象來取代,這樣做的一個(gè)優(yōu)點(diǎn)是,我們可以實(shí)現(xiàn)自上而下的設(shè)計(jì)方式:在下層的具體實(shí)現(xiàn)還沒有確定的情況下,只要能夠在抽象層面將接口確定,就能夠完成上層的設(shè)計(jì)與開發(fā),這同樣給可測(cè)試性帶來便捷
除了以上所述的SOLID原則之外,還有以下幾個(gè)關(guān)鍵的設(shè)計(jì)原則可供參考:
- 組件設(shè)計(jì)應(yīng)該是高內(nèi)聚的:相信大家都很熟悉這點(diǎn)了,就不多說了。例如:不要將數(shù)據(jù)訪問邏輯寫進(jìn)領(lǐng)域模型的業(yè)務(wù)邏輯中,這與上述單一職責(zé)原則是密切相關(guān)的
- 將Cross-Cutting的代碼從特定于應(yīng)用程序的邏輯中分離開來:Cross-Cutting的代碼是一些面向橫面的代碼,比如安全、操作管理、日志以及測(cè)量/計(jì)量系統(tǒng)等。將這些代碼與應(yīng)用系統(tǒng)業(yè)務(wù)邏輯混在一起會(huì)增加系統(tǒng)的復(fù)雜性,給將來的擴(kuò)展和維護(hù)造成很大的麻煩。這與面向方面編程(ASPect-Oriented Programming,AOP)有關(guān)
- 關(guān)注點(diǎn)分離(Separation of Concerns,SoC):將應(yīng)用系統(tǒng)分成多個(gè)子部分(子系統(tǒng)),各個(gè)部分之間的功能盡量不要重復(fù),其目的就是為了減少交互點(diǎn),以實(shí)現(xiàn)高內(nèi)聚和低耦合
- Don’t Repeat Yourself(DRY):一個(gè)特定的功能只能在某個(gè)特定的組件中實(shí)現(xiàn)一次,同樣的功能不要在多個(gè)組件中重復(fù)多次
- 避免YAGNI(You Ain’t Gonna Need It)效應(yīng):只考慮和設(shè)計(jì)必須的功能,避免過度設(shè)計(jì)
好了,本講就介紹到這里,估計(jì)對(duì)大多數(shù)接觸過架構(gòu)的軟件朋友來說,本講的部分內(nèi)容都是廢話。下一講開始,我會(huì)花部分筆墨在DDD/DDDD的分層介紹上,雖然有可能還是廢話,但這對(duì)我們理解NLayerApp的解決方案組織結(jié)構(gòu)會(huì)有相當(dāng)?shù)膸椭?/p>
NET技術(shù):Microsoft NLayerApp案例理論與實(shí)踐 - 多層架構(gòu)與應(yīng)用系統(tǒng)設(shè)計(jì)原則,轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。