1. 程式人生 > >.Net企業級應用架構設計之業務層設計

.Net企業級應用架構設計之業務層設計

業務層剖析

任何複雜的任何軟體都可以通過層來組織,每一層表示系統中的一個邏輯部分,一般來說,業務邏輯層中的模組包含了系統所需要的所有功能上的演算法和計算過程,並於資料層和表現層互動。抽象的說,業務邏輯層是軟體中專門處理業務相關任務效能的部分。

業務邏輯層表示了系統的邏輯,此處的程式碼將要進行必要的決斷並執行操作。前面談到過安全性,在業務邏輯層的安全性意味著使用基於角色的安全原則,僅允許認證使用者訪問特定的業務物件。從外界看,業務邏輯層可以看作是一個操作業務物件的機制,一般來說,業務物件不過是某個領域實體的實現,或者是某類輔助型別,用來執行一些計算。業務邏輯層處於分層系統的中間位置,業務邏輯層的輸入和輸出不一定是業務物件,很多時候,架構師更傾向於使用資料遷移物件在層之間交換資料。

資料遷移物件和業務物件之間的取捨一直是團隊中爭議的話題。建議使用資料遷移物件的理論認為,資料遷移物件能減少層之間的耦合,使系統更加整潔乾淨。不過在現實中,人們都會說複雜性已經很高,因此應該避免增加任何不必要的物件。一條實用的原則是,當已經有了數百個業務物件時,或許並不應該僅僅為了設計的乾淨而讓這個數字加倍,在這種情況下,資料遷移物件通常就是業務物件。業務物件同時包含了資料和行為,是一個可以參與到領域邏輯的完整物件。而資料遷移物件更像是一種值,即一系列資料的容器而沒有相關的行為。為了序列化,業務物件中的資料會複製到資料遷移物件中。除了get/set訪問器之外,資料遷移物件沒有邏輯行為。資料遷移物件並不僅僅是領域物件去掉了行為,它表示了特定領域物件的一個子集,用於專門的上下文中。一般來說領域物件是一個物件圖,而資料遷移物件僅僅是所需要部分資料的投影而已。

每個真實的世界組織都是基於一系列業務規則執行的。或許很多人沒有認識到組織中存在的這些規則,但不能否認這些規則的存在。每個組織都有自己要實現的戰略,而業務規則是保證實現這些戰略的主要手段。戰略決定了組織的發展方向,而業務給出了實現戰略的具體做法。

業務物件的屬性來自於其對映的實體的屬性,業務物件的方法來自於其自身的職責以及應用到該實體上的部分業務規則。業務規則在很多程度上是對資料的驗證。換句話說,很多業務規則說到底就是驗證某個業務物件的當前內容。按照這樣的理解,若有專門的驗證層,並讓業務物件可選擇的支援,這個設計將會非常不錯。

業務邏輯層不應該看作是一個整體的元件,或者一些不相關模組的組合。多年的實際經驗告訴我們,業務邏輯層在其他層(經典三層)中適當的重複是可以接受的,也是很多程式的做法。不過這種做法有一定的限度,且不應該受到鼓勵。

業務層和其他層

假設我們有一個經典的分層系統,分為表現層、業務層和資料訪問層,那麼業務邏輯分佈在各個層中的百分比應該是多少?最權威的答案是0 - 100 - 0 。這個數字顯然不現實,通常你應該嘗試把所有的事情放在業務邏輯層完成,除了CRDU操作以及使用者介面的調整。分散在表現層和資料訪問層中的邏輯有可能只是處於效能方面的考慮才進行的重複。這些重複由一些系統總體功能的灰色地帶導致,有時候我們都不知道該把他們放在何處,下面介紹幾個常見的灰色地帶。

1、資料格式化。若在客戶端進行視覺化,那麼表現層必須瞭解很多上下文以及系統的邏輯。若將格式化放在業務邏輯層,那麼業務邏輯層就必須提供合適的方法,供客戶端呼叫並獲取可以直接顯示的字串。我們會有幾個選擇,第一是存放兩個資料,原始資料和格式化之後的資料。第二是存放原始資料,需要時格式化。第三是按照輸入時的格式直接存放。我們當然會選擇第二種。

2、CRUD操作。資料訪問層應該僅僅用來處理資料庫相關的操作,而業務邏輯判斷又必須呼叫資料。

3、儲存過程。原因類同與CRUD訪問。在涉及到資料庫流量的問題時,基本可以通過新增硬體或更換更好的硬體來解決,此外,在業務邏輯層中可以進行適當的快取。

業務層的模式區分

在業務層的模式上有幾種選擇。首先是過程式模式,在面向物件開發興起之前,業務邏輯只不過是一系列過程的集合,每個集合都用來處理來自於表現層的一個請求。因此好的設計都在於更好的去組織這些過程,減少程式碼和流程的冗餘。基於物件的模式抽象程度越高,與資料模型的差距也會越大,因此若想建立一個領域驅動的物件模型,一般應該從領域著眼,而不是從資料庫結構開始。領域驅動的設計一定會使資料庫模型和領域模型之間存在不小差異。這個模式通常叫做領域模型。

基於物件的模式在開始時代價較高,但隨著複雜性增長,其代價基本上也線性增加。換句話說,一旦你對領域模型有足夠的瞭解,無論系統的複雜性如何,你都可以使用領域模型模式。在複雜性度量上,複雜性分為兩方面,第一種是天生的,不可避免,無法協調需求本身,這類複雜性可以通過一些方法或多或少降低,不過不可能完全抹除,必須直接面對。第二種是來自於引入的複雜,這個來自於不同專案干係人意見的不協調,負面效果就是將團隊引向錯誤的方向,錯誤的方向則會讓抽象設計包含不必要或非功能性的功能,將軟體逼上絕路。

需求的數量可以用來粗略判斷系統的複雜性,認識到複雜性比解釋如何找到複雜性更加簡單。

事務指令碼模式

事務指令碼模式可能是業務邏輯層中最簡單的模式了,它是一個純粹的過程式模式。事務指令碼模式鼓勵你放棄所有的面向物件設計,將業務直接對映到需要的使用者操作上,該模式的關注點在於使用者通過表現層所能執行的操作,併為每個操作編寫一個專門的方法。事務指令碼模式易於理解和解釋,每個必須的使用者操作都在一個物理事務中開始。直至結束,不過資料訪問通常被封裝在另一些元件中,並不屬於指令碼。事務指令碼適合應用於那些業務邏輯非常簡單,且最好不大可能改變的簡單場景中。在這個簡易度和複雜性的概念上權衡非常艱難,更為重要的是,對簡單和複雜的認知還依賴與一個人的態度和能力。你懂的!

簡單是事務指令碼模式最值得一提的優勢,但是事務指令碼有造成程式碼重複的潛質。所有實現了事務指令碼的型別都可以看做是業務元件。每個業務元件都可以有一個或多個事務。比較流行的設計方式是將各個事務指令碼分組,然後讓每一組成為一個業務元件,這樣每一組中的事務指令碼在邏輯上都是相關的。另一種做法是將每個事務指令碼用單獨的類封裝起來,這樣每個業務元件都僅包含一個方法,換句話說,這裡的業務元件就變成了一堆命令物件。若想將事務指令碼的業務元件設計成命令物件,可以釋放出一個介面,並將所有需要的引數以型別公有屬性的形式暴露出來。

表模組模式

與事務指令碼相比,表模組更有結構,表模組作為一個容器,將資料和行為組合在一起。業務邏輯被拆分為粗粒度的、表示整個資料表的元件。表模組的粒度不會下降到資料行的程度,即表模組類無法區分每一行資料。表模組模式應用中,使用基於記錄集的資料結構是最常見的方式。例如Dataset、Datatable等。

對那些不需要太多抽象,且資料模型和物件模型之間沒有太大差異的場景,表模組是個非常不錯的折衷方案。與事務指令碼相比,表模組基於一個概念模型。而不是一大批方法的鬆散集合。若系統中的表現層和資料訪問層都是基於表狀資料結構,那麼表模組將是非常好的選擇,這時,業務層即可為表現層提供直接可用的資料,有時甚至可以直接通過資料繫結實現。

表模組並沒有比事務指令碼複雜很多,不過若完全需要手工構造,那麼花費的時間可能比簡單的事務指令碼多出很多。模式在提供了更多指導的同時,也意味著我們需要考慮更多規則,也就是編寫更多程式碼。

內嵌的Dataset設計器提供Fill和GetData方法來基於整個資料表進行查詢。從概念角度講,表模組的另一個優勢在於,無論底層資料來源是什麼,對於同一些功能都會得到同樣的表模組類。表模組基於物件,但完全由資料庫驅動。表模組並不適合表述複雜的眾多實體。特別是物件模型和資料模型之間有顯著差距的時候。表模組的優勢是VS提供了強大的支援,實現起來簡單,不過考慮到這些生成的程式碼類似於一個黑箱,優勢也就成了劣勢。當然,表模組這個結構模型不一定需要和VS緊密耦合。

活動記錄模式

事務指令碼和表模組都是過程式模式。但是表模組基於物件,不是一個對於基於物件業務邏輯建模模式。最終走向面向物件設計關鍵的一步是你認識到系統中的目標物件,業務邏輯和領域邏輯才是系統的核心,它是由實體之間必須的互動組成的。

活動記錄是一種應用於相對簡單的領域模型,但仍基於物件模式。另一種更加容易理解的說法是,活動記錄基於資料表中的行,而不是表模組那樣基於資料表。也就是說,活動記錄對資料有行級別的粒度,而表模組關注的是整張表。活動記錄模式歸為資料來源設計模式,而不是業務邏輯模式。活動記錄模式就是指一個封裝了資料表或檢視的一行的物件,物件中可以同時包含資料和行為,活動記錄物件的結構應該儘可能地接近於相關聯的資料表結構。

在那些沒有服務層的應用程式中,活動記錄模式可以和事務指令碼結合使用。

活動記錄模式的成功依賴於兩個因素:簡單和框架。這兩個因素緊密相關。我們最常見和熟悉的是LINQ- to - SQL。相對於簡單的邏輯來說,活動記錄非常合適。活動記錄的另一個問題是物件和資料庫表設計之間的繫結。若你不得不修改資料庫,那麼同時也要修改活動記錄物件模型以及所有相關程式碼,從這個角度看,活動記錄站在了領域驅動的對立面。

領域驅動模式

在設計領域邏輯時,若選用了過程式方法或活動記錄模式,那麼實際上採取的是以資料為核心的做法。驅動業務模型設計的並不是業務本身,而是業務中使用到的資料。

從長遠看,以資料為中心的方法並不能很好的適應規模的增加。因為當系統的複雜性達到某個極限之後,哪怕是再新增一些新的需求,都會成為難處理的問題。領域模型關注於系統的期待行為以及系統正常工作所需要的資料。領域驅動設計力求將複雜性控制在一個可控(雖然仍舊很高)範圍內,選用領域驅動設計並不一定需要使用領域模型模式,不過領域模型模式是最自然的選擇。

領域模型描述了系統中涉及的實體,捕獲了實體之間的關係以及資料在其中交換的過程。領域模型此刻還並不是一個軟體,也不涉及任何軟體或實現上的概念或原則。領域模型只是一個正式的模型,用來讓技術團隊和業務團隊彼此理解並能良好交流。領域模型可以看作是活動記錄的“大哥”,領域模型完全和資料庫獨立,是一個儘可能貼近真實流程的模型。領域模型模式使系統建模非常自由靈活,無需考慮平臺和資料庫的約束。此外,領域驅動設計是一種看待設計的方式,因此技能和態度起到了重要的作用。

在領域模型中,概念是用來建模的,這種做法充分利用了面向物件設計的優勢,你可以使用到面向物件的所有特性,包括封裝和繼承,而同時又無需受到資料庫結構的限制,這就意味著實體並不會察覺到絲毫有關底層使用的持久化機制。領域模型是由需求驅動的,且僅需要你理解問題領域,並用類對於邏輯建模。實現領域模型主要的障礙是物件和關係型資料庫之間的不匹配,領域模型是一個面向物件的設計,和資料庫或其他應用程式的約束完全無關,而今受限於其建模的業務流程,這意味著同樣的領域模型可以重用於其他需要同樣邏輯的任意場景。模型是和業務相關的,且僅和業務相關。

若沒有任何O/R對映工具,例如NHibernate,那麼很難實現領域模型模式。

小結

業務邏輯是系統的核心,不過並不是整個系統。業務邏輯設計上的選擇將會影響到其他層,特別是持久化和資料訪問層,這兩個層加起來,就會專案的成敗產生決定的影響。

相關部落格: