Microsoft NLayerApp案例理論與實踐 - 多層架構與應用系統設計原則

作者: dax.net  來源: 博客園  發布時間: 2011-03-10 17:00  閱讀: 1492 次  推薦: 1   原文鏈接   [收藏]  
摘要:本文將帶大家學習分層/多層架構與應用系統設計原則。

  在對NLayerApp實際項目進行討論之前,讓我們首先學習一下(或者應該說重溫一下)分層/多層架構與應用系統設計原則。很多朋友會認為這些都是老掉牙的內容,只要是軟件從業人員,都會對這些內容非常熟悉。然而,果真如此嗎?我在這里整理這部分內容,一方面是為介紹NLayerApp打下基礎,而另一方面,則是希望借此機會將這些理論性的東西做個歸納,也希望讀者朋友能夠認真閱讀,畢竟溫故知新嘛。

  需要說明的是,從本章節開始,大多數理論性的東西都源自Microsoft Spain團隊針對NLayerApp所編寫的《Architecture Guide Book》,事實上這本Guideline的英文版至今也還沒有完成,我會從中抽出部分章節做些翻譯和歸納,有興趣的朋友請直接上microsoftnalyerapp.codeplex.com站點上下載英文版閱讀。

  Layers與Tiers

  對Layers與Tiers這兩個單詞進行區分是非常重要的。從中文翻譯看,兩者都是層的意思,因此我們往往會將這兩個概念弄混。Layer一詞更多的是表示對系統組件或功能的邏輯區分,它并沒有包含將組件分布到不同的區域、不同的服務器上的意思。而Tier則是表示系統組件和功能在服務器、網絡環境以及遠程位置的物理部署。盡管這兩個概念同時使用者非常相近的一些術語,比如展示、服務、業務和數據等,但我們必須了解它們之間的差別。下面這幅圖表明了多層(N-Layer)邏輯架構與三層(3-Tier)物理結構之間的差異:

image

  需要注意的是,對于具有一定復雜度的應用程序而言,采用多層(N-Layer)邏輯架構的實現方式是非常必要的,這會降低系統的復雜度,并在設計、開發、測試、部署及維護等各個環節為應用系統帶來高可用性、高延展性等正面效應。然而,并非所有的應用程序必須以三層(3-Tier)/多層(N-Tier)物理結構進行部署,我們可以將多個邏輯層部署在同一臺機器上,也可以根據需求,將這些邏輯層部署在網絡中的不同機器上。

  邏輯分層(Layer)的設計

  在討論DDD的分層之前,先讓我們看看傳統的分層方式。就像上文所述,我們應該根據項目的實際需求,將組件/功能模塊合理地劃分到邏輯層中。同一層中的組件,應該是高內聚的,并具有相同的抽象層次。層與層之間應該低耦合。對于以分層設計的應用程序而言,最關鍵的問題就是如何處理層與層之間的依賴關系。考察傳統的多層架構應用,處于某層的組件,只能對同層或下層的其它組件進行訪問,這樣做可以有效地降低層與層之間的依賴關系。通常會有兩種分層設計:嚴格分層與靈活分層

  1. 嚴格分層迫使組件只能訪問同層的其它組件,或者只能訪問直接下層的其它組件,于是,第N層的組件只能訪問第N或N-1層的組件,而第N-1層的組件只能訪問第N-1或N-2層的組件,以此類推
  2. 靈活分層允許組件訪問同層的其它組件,以及所有下層的其它組件,于是,第N層的組件可以訪問第N或N-1、N-2…層的組件

  使用靈活分層的架構可以提高系統性能,因為這樣的結構無需引入過多的請求/反饋的傳遞操作,因為一個層可以直接訪問位于其下的任何層;而嚴格分層卻降低了層與層之間的耦合性,對低層的修改不會對整個系統造成廣泛的影響。根據Eric Evans在其《領域驅動設計-軟件核心復雜性應對之道》一書中的描述,DDD的分層選用的是靈活分層模式。

  讓我們再把討論的粒度細化,來看看層中的組件與組件之間的關系。事實上,在很多復雜的應用中,位于同一層的組件與組件雖然具有相同的抽象層次,它們也不一定是高內聚的。因此,我們可以引入模塊(Module)的概念,將同一層中高內聚的組件放在同一個模塊中,于是,每個層又會由一個或多個高內聚的子系統(模塊)所組成,如下UML組件圖所示:

image

  使用分層架構,有如下幾點好處:

  • 提高系統的可測試性
  • 對解決方案的維護和管理變得更加簡單。層內高內聚、層間低耦合的結構,使得系統實現與分層組織方式變得非常靈活方便
  • 其它外部應用程序能夠非常方便地使用不同的層所提供的特定功能
  • 當系統以層的方式進行組織時,分布式開發也變得非常簡單易行
  • 在某些情況下,分層系統的物理部署方式能夠給系統帶來延展性,當然,應該有效地評估具體的實踐方式,因為這種做法有可能損傷系統性能

  應用系統基本設計原則 - SOLID

  應用系統的設計應該遵循一些基本的設計原則,這能幫助你有效地創建一個低成本、高可用、高可擴展的應用程序。在這里,我們引入一個SOLID設計原則,SOLID由如下幾點構成:

  • Single Responsibility Principle(單一職責原則)
  • Open Close Principle(開-閉原則)
  • Liskov Substitution Principle(里氏替換原則)
  • Interface Segregation Principle(接口分離原則)
  • Dependency Inversion Principle(依賴反轉原則)

  下面簡要介紹一下這幾個原則。

  • 單一職責原則:每個類應該只有一個獨一無二的職責,或者說每個類只能有一個主要功能,由此派生出一個結論:每個類應該盡可能少地依賴于其它類
  • 開-閉原則:每個類,應該對擴展進行開放,而對修改進行封閉,也就是支持擴展,而不是支持修改:類中的方法可以通過繼承關系進行擴展,而不會改變類本身的代碼
  • 里氏替換原則:子類可以被基類型(基類或者接口)替換。應用程序依賴抽象運行,其行為不會因為具體實現的改變而更改,應用程序應該依賴于抽象(基類或者接口),而不是具體實現。接下來將要討論到的依賴注入(Dependency Injection)就與這條原則有關
  • 接口分離原則:接口的職責也應該是單一的,接口中應該包含哪些方法,需要進行嚴格的評估,如果其中某些方法的職責與接口的本身定義不相符合,則應該將其分離到其它接口中。類需要根據其調用者所需要的不同接口類型,來暴露不同的接口
  • 依賴反轉原則:抽象不能依賴于具體,而具體則應該依賴于抽象。類之間的直接依賴應該用抽象來取代,這樣做的一個優點是,我們可以實現自上而下的設計方式:在下層的具體實現還沒有確定的情況下,只要能夠在抽象層面將接口確定,就能夠完成上層的設計與開發,這同樣給可測試性帶來便捷

  除了以上所述的SOLID原則之外,還有以下幾個關鍵的設計原則可供參考:

  • 組件設計應該是高內聚的:相信大家都很熟悉這點了,就不多說了。例如:不要將數據訪問邏輯寫進領域模型的業務邏輯中,這與上述單一職責原則是密切相關的
  • 將Cross-Cutting的代碼從特定于應用程序的邏輯中分離開來:Cross-Cutting的代碼是一些面向橫面的代碼,比如安全、操作管理、日志以及測量/計量系統等。將這些代碼與應用系統業務邏輯混在一起會增加系統的復雜性,給將來的擴展和維護造成很大的麻煩。這與面向方面編程(Aspect-Oriented Programming,AOP)有關
  • 關注點分離(Separation of Concerns,SoC):將應用系統分成多個子部分(子系統),各個部分之間的功能盡量不要重復,其目的就是為了減少交互點,以實現高內聚和低耦合
  • Don’t Repeat Yourself(DRY):一個特定的功能只能在某個特定的組件中實現一次,同樣的功能不要在多個組件中重復多次
  • 避免YAGNI(You Ain’t Gonna Need It)效應:只考慮和設計必須的功能,避免過度設計

  好了,本講就介紹到這里,估計對大多數接觸過架構的軟件朋友來說,本講的部分內容都是廢話。下一講開始,我會花部分筆墨在DDD/DDDD的分層介紹上,雖然有可能還是廢話,但這對我們理解NLayerApp的解決方案組織結構會有相當的幫助。

1
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()