|
前言
記得幾個月前,在一次北京博客園俱樂部的活動上,最后一個環節是話題自由討論。就是提幾個話題,然后大家各自加入感興趣的話題小組,進行自由討論。當時金色海洋同學提出了一個話題——“什么是業務邏輯”。當時我和大家討論ASP.NET MVC的相關話題去了,就沒能加入“業務邏輯”組的討論,比較遺憾。
其實,一段時間內,我腦子里對“業務邏輯”的概念也是非常模糊的。但在不斷地閱讀、思考和實踐過程中,這個概念及其相關的內容才在我腦子里漸漸清晰。我想,很多朋友也許也對這個概念不是很了解,所以愿意結合既有資料和自己的思考,總結一篇關于業務邏輯的概述性文章,一則與朋友們分享探討,二則也是為自己對業務邏輯的學習做一個總結和提升。因為我還不敢說對業務邏輯內涵及外延理解的非常充分,所以文中如有不當之處,還請各位不用客氣,盡管批評就好!
內容提要
===================前篇=====================
前言
內容提要
1、我把業務邏輯丟了!——找回丟失的業務邏輯
2、細說業務邏輯
2.1、業務邏輯到底是什么
2.2、業務邏輯的組成結構
2.2.1、領域實體(Domain Entity)
2.2.2、業務規則(Business Rules)
2.2.3、完整性約束(Validation)
2.2.4、業務流程及工作流(Business Processes and Workflows)
2.3、業務邏輯層職責相關爭議
2.3.1、爭議一:數據的格式化
2.3.2、爭議二:數據合法性及完整性驗證
2.3.3、爭議三:CRUD
2.3.4、爭議四:存儲過程
===================后篇=====================
3、業務邏輯的架構模式及實現
3.1、Transcaton Script
3.1.1、概述
3.1.2、分析
3.1.3、.NET平臺實現示例
3.2、Table Module
3.2.1、概述
3.2.2、分析
3.2.3、.NET平臺實現示例
3.3、Active Record
3.3.1、概述
3.3.2、分析
3.3.3、.NET平臺實現示例
3.4、Domain Model
3.4.1、概述
3.4.2、分析
3.4.3、.NET平臺實現示例
3.5、各種架構模式的比較及選擇
4、結束語
參考文獻
1、我把業務邏輯丟了!——找回丟失的業務邏輯
相信朋友們基本都是軟件開發人員。不論身處什么職位,我們的工作都有一個共同的目標——制作軟件產品。而所謂的軟件產品,一定是在某個領域內去實現某些業務。如此看來,“業務邏輯”本應和“軟件產品”是緊緊綁在一起的,沒有業務邏輯,何來軟件產品?
但是,我發現一個奇怪的現象,一說業務邏輯,很多人就無法形成清晰地印象。例如,經典的三層架構:表示層、業務邏輯層和數據訪問層,一提到表示層或數據訪問層,大家腦子里馬上能產生出清晰的概念,但一提到業務邏輯層,就有點模糊了,或者完全不知道其是什么,或者有個模糊的輪廓,但對其具體的職責、結構不是很清楚。真是奇了怪了!我們天天和業務邏輯打交道,搞不清業務邏輯是什么。
對于這個奇怪的現象,我思前想后,結合自身的教訓(我也曾很長時間搞不清業務邏輯),終于弄清楚了其原因——這和我們接觸這個概念的途徑和認知結構有莫大關系。
不知道有多少人和我一樣,首次接觸“業務邏輯”這個概念是從分層架構中的“業務邏輯層”概念開始的,我相信不在少數。事情壞就壞在這里!為了讓朋友們直觀看清“業務邏輯”的概念是怎么被我們丟掉的,請大家看一個圖,這個圖展示了很多人對“業務邏輯”的認知過程。
圖1-1、狹義的認知分解過程
如圖1-1所示,我們先接觸了分層架構,然后對每個層產生了初步的認識。其中,由于表示層和數據訪問層的代碼職責清晰明確,基本能正確認識。但是,由于我們接觸的分層架構的Demo大多業務極其簡單,又基本是CRUD操作集中型的業務。所以,我們腦子中就產生了疑問:這個所謂的業務邏輯層是干什么的?怎么就簡單封裝了一下數據訪問層的操作?這有存在的必要嗎?由于有了這種“先入為主”的誤導,使得很多朋友腦中將“業務邏輯”和“業務邏輯層”兩個概念混淆了,始終想不明白這東西到底是什么,做什么用的。再加上很多朋友所看的、所做的系統都是CRUD操作集中型的,就形成了“業務邏輯貌似就是對數據訪問操作的簡單封裝”這一片面概念。
到底這一概念有沒有錯呢?其實沒錯,因為在簡單的、CRUD操作集中型軟件中,業務邏輯基本就是對數據訪問簡單的封裝。但是,無錯不代表全面,這是一種狹義的業務邏輯理解,而且是狹義中的狹義。為什么這么說呢?因為我們不但是在“業務邏輯層”這么一個狹義范圍內去理解業務邏輯,而且還是CRUD集中型操作這種“非常瘦”的業務邏輯層范圍內去理解,所以,可謂是在狹義的基礎上的狹義。
當我們把這么一個“狹義中的狹義業務邏輯”與“業務邏輯”等同起來時,誤會、迷茫、困惑、不屑就出現了。這就如同,給你一只溫順的哈巴狗,還是病怏怏的、無精打采的小哈巴狗,而你把這只“病怏怏的小哈巴狗”與“狗”的概念等同起來了。那么你一定就會為有人養狗看家和警察養狗當警犬抓壞人而困惑:這東西這么弱小,我一腳就踩死了,怎么弄用來看家和抓壞人呢?進而可能會產生“狗狗無用論”,“狗狗廢品”等觀念。當然,在現實中,很少有人只見過小哈巴狗而沒見過狼狗等其它狗類,所以,故事中的誤會對“狗”一般是不存在的。但在現實中,確實有很多人只見過業務邏輯中的“小哈巴狗”,卻沒有見過業務邏輯中的“狼狗”、“藏獒”,所以,這種誤會在對“業務邏輯”的理解上廣泛存在。
那么,廣義的情況究竟是怎么樣的?請看下圖。
圖1-2、廣義的認知分解過程
(注意!凡是不特別說明,下文中所有“數據”一詞都指需要持久化的數據,而不包括內存中的臨時數據。請各位留心。)
如圖1-2所示,廣義的認知分解應該是這樣的:軟件產品都是在某個領域內實現某些特定業務,所以,軟件產品天生應該分解為界面交互部分和業務邏輯部分,其中業務邏輯部分是軟件產品的核心,它客觀存在于軟件產品內部,但是無法對使用者產生直觀刺激,因此業務邏輯不能與使用者直接交互。而界面交互部分是業務邏輯與使用者進行交流的接口,使用者通過界面交互部分,與業務進行交流,從而使得軟件產品發揮其作用。
而在具體實現系統時,界面交互部分演化成表示層,業務邏輯部分演化成業務邏輯層。所以,可以認為,數據訪問層不是軟件產品自然演化的直接產物,之所以出現數據訪問層,是因為某些產品的業務屬于“數據操作集中型”業務,為了實現隔離、復用等目的,架構師從業務邏輯中分離出了頻繁使用的數據訪問業務,形成了單獨的數據訪問層。從廣義來說,可以認為數據訪問隸屬于業務邏輯,因為,數據訪問操作實際上也是業務邏輯的一部分。
總結一下幾個要點:(這幾個要中的業務邏輯均指廣義業務邏輯)
1)軟件產品自然的可分為界面交互部分和業務邏輯部分。
2)從空間結構上看,業務邏輯和數據訪問不是并列關系,而是隸屬關系——數據訪問隸屬于業務邏輯。雖然在具體系統實現層面,數據訪問層和業務邏輯層是并列存在,但從概念本質層面上分析,兩者是隸屬關系。
3)從時間結構上看,應該是先有業務邏輯的概念,才有數據訪問的概念。業務邏輯衍生自軟件本身,數據訪問衍生自業務邏輯。
4)因為業務邏輯是軟件產品自然的一部分,所以擁有業務邏輯是軟件產品的必要條件(讀者可以試著舉出一個不包含業務邏輯的軟件)。但是一個軟件可以沒有數據訪問,如“計算器”、“不帶存檔的小游戲”等。
利用以上論述要點和認知分解,朋友們可以試試在腦中重新構筑狹義和廣義“業務邏輯”的概念。看能不能把我們丟掉的業務邏輯概念找回來。關于業務邏輯更多的細節,將在下文中討論。
2、細說業務邏輯
2.1、業務邏輯到底是什么
在第一大節里說了那么多,相信各位基本已經形成“業務邏輯”的概念了。如果我在這里再啰嗦什么,我不嫌累各位也要嫌煩了。所以,這里我僅給出兩個定義。
廣義上的義務邏輯——軟件本身固有的一種品性,自然存在于軟件產品內部,是軟件具有的在某個業務領域內的邏輯,是軟件的核心和靈魂。軟件產品除界面和交互外的一切都可看作是廣義業務邏輯。
狹義上的業務邏輯——等同于分層架構中“業務邏輯層”的職責,是軟件中處理與業務相關任務的部分,一般狹義上的業務邏輯不包含數據持久化,而只關注領域內的相關業務。
對于以上兩種定義,希望朋友們不要割裂開來看,而 要辯證統一的去看,這樣,才能構建一個完整而辯證統一的“業務邏輯”概念。在下文中,將不再明確區分狹義和廣義,“業務邏輯”一詞將代表兩者的辯證統一體。
2.2、業務邏輯的組成結構
業務邏輯作為一個高層次概念,其內在結構也是非常豐富的,下面我們深入其里,去探尋一下業務邏輯都是由哪些更底層的部分構成的。
2.2.1、領域實體(Domain Entity)
通俗的說,領域實體就是這個領域內有哪些東西。例如,銀行業領域內有賬戶、支票、前臺營業員等實體;B2C電子商務領域有商品、訂單、交易等實體;魔獸世界游戲的領域內有角色、種族、道具、魔法等實體;高等代數領域有矩陣、行列式等實體。
領域實體是某個領域內各種對象的抽象,可以用名詞表示(可以是具體名詞或抽象名詞,甚至動名詞,只要其具有名詞性),構成了整個業務邏輯的骨骼和靜態模型。一般每個領域實體有自己的一些屬性和行為。順便說一句,領域實體的存在時OOA&D的基礎。
在具體的軟件系統中,領域實體往往會根據架構的不同有不同的映射存在形式。
其中一種叫做Business Object(BO),即業務對象,某些文獻稱其為“充血實體類”,這種對象完整抽象了領域內的某個實體,封裝了此實體相關屬性和行為。在面向對象的設計和架構中,這種實體類很常見。
另一種叫做Data Transfer Object(DTO),某些文獻稱其為“貧血實體類”,其特點是僅有屬性,不存在行為。這種實體類主要負責整體性傳遞數據。另外,與BO不同的是,DTO可以不抽象領域實體的全部屬性,而只根據需要抽象一部分。例如,某個“User”實體存在很多屬性,但如果某個方法僅需要其聯系方式,可以設計一個DTO,僅有id,email,address,phone等就夠了。在面向過程的設計和架構中,這種實體設計比較常見。
2.2.2、業務規則(Business Rules)
業務規則就是某個領域內運作的規則,構成了整個業務邏輯的靈魂和動態模型。業務規則作用于領域實體,領域實體遵從業務規則進行運作。
如:在銀行領域內,“轉賬時從A賬戶扣除相應款項,在B賬戶添加相應款項,并從A賬戶扣除相應手續費,并通過某些途徑通知A和B賬戶的戶主”就是一條規則。需要注意的是,業務規則比較抽象,并不是需求,需求需要具體且無二義性,而業務規則只是抽象的一種描述,例如,通知戶主的途徑是什么?電子郵件?電話?短信?并沒有具體描述,但在規則中有“通知”這一項,因此不能將業務規則等同于需求。
2.2.3、完整性約束(Validation)
領域實體和業務規則構建了業務邏輯的主體,但在這主體之上,還存在著一個限制,這就是完整性約束。
完整性約束是對業務領域中的數據、規則的強制性規定與約束。這種約束是系統正常運轉的保證。
如“賬戶密碼不能為空”,“身份證號必須符合具體格式規定”,“轉賬流程必須具有原子性,A賬戶扣錢、B賬戶存錢、A賬戶扣除手續費、通知戶主四項操作必須要么都做,要么都不做”,都是完整性約束。
2.2.4、業務流程及工作流(Business Processes and Workflows)
有了上述三項,業務邏輯還不能正常工作,因為還沒有“啟動器”和“過程托管器”。設想我們有了各種實體類,它們有各自的屬性和行為,也有定義好的業務規則和完整性約束。現在實體類僅僅具有實現業務規則的能力,但它們如何啟動并交互協調完成業務規則呢?因此我們需要有東西去觸發和協調實體。
業務流程或工作流是啟動及托管協調領域實體完成既定規則的過程。例如,“在線訂購”是一個業務流程,它包括“用戶登錄-選擇商品-結算-下訂單-付款-確認收貨”這一系列流程。各個實體如會員、訂單、商品等已經包含了完成在線訂購必要的行為,但仍需一個流程,才能真正完成業務。
具體到程序中,業務流程也許通過一個方法來實現,這個方法負責啟動并協調各個實體類,完成一個流程。
2.3、業務邏輯層職責及相關爭議
2.3.1、數據的格式化
關于數據的格式化應該放在業務層進行還是表示層進行一直存在爭議。我個人的意見是這樣的:
業務層送給表示層的數據應該具備以下要求。1)返回的數據應該完成了所有必要的業務處理和業務計算。例如,若返回訂單信息讓表示層展示,會有個必要的數據——訂單總額。這個數據需要首先用各個訂單項的單價乘以數量,然后加和。那么,這個數據應該在業務層完成計算直接返回,總之不應讓表示層進行任何業務處理和計算操作。2)一次性返回所有需要的數據,避免表示層再一個Action里調用多次業務。打個比方,例如訂單中有個“客戶姓名”,這個數據不保存在訂單表中,而是通過外鍵關聯的,那么,業務層應該將“客戶姓名”一并取出返回給表示層。總之,避免表示層在一個Action里多次調用業務層。3)不攜帶任何格式信息,僅僅是結構良好的純凈數據,如DTO形式。因為,數據如何展示,是表示層的職責,如何在業務層中返回了過多格式信息,就會造成表示層的修改困難。例如,我曾聽說過所里承接的一個實際項目,開始是使用B/S,當時他們的業務層返回的數據全都附帶了html代碼。后來,客戶嫌B/S響應不夠迅速(可能是客戶公司的網絡條件不好),要求改成C/S,當時全傻眼了,貌似幾乎修改了整個業務層。那個項目相當龐大,7個子系統,投入200人開發了1年多,想想修改的難度吧。
2.3.2、數據合法性及完整性驗證
一般做系統,都避免不了數據驗證。上文曾經提到,完整性約束是業務邏輯的一部分。如此看來,數據驗證一般應該放在業務層。但是,實際情況并不盡然。個人認為數據驗證的方式,目前沒有統一標準,可以根據需要放在表示層或業務層。但是,我個人不提倡在“表示層的服務端”放置過多完整性驗證。因為,表示層的職責應該僅僅是接收數據并傳遞給業務層,不應對數據是否合法負責。過多的數據驗證,不但令表示層代碼臃腫,而且使得表示層職責變得不明確。
可以在“表示層的服務端”放置一些簡單的驗證,如空值驗證,兩次輸入密碼是否一致等,但業務關系緊密的驗證,最好放在業務層。甚至有些驗證只能在業務層驗證,如“當前用戶名不能與已有用戶名重復”,這種驗證需要訪問持久化數據,需要由業務層完成。
這里之所以強調“表示層的服務端”,是因為一般在B/S系統中,都會在JavaScript里加入一些基本的數據驗證,如空值檢查,格式正則匹配等。這主要是為了減輕服務器負擔,將大多數顯然包含不合法數據的請求拒絕掉,而不發給服務端驗證。當然,因為可能會出現JS被屏蔽或黑客惡意攻擊行為,所以,所有驗證不論JS中是否驗證過,服務端(可能是表示層的服務端部分或業務層)一定要再進行驗證。
2.3.3、CRUD
CRUD,即常說的增刪改查操作。關于CRUD是否是業務層的職責,一直也是爭議不斷。因為目前并沒有權威的定義,所以這里我斗膽說一下我對這個問題的看法。還請大家批判性閱讀。
一說到“增刪改查”,大家一定會覺得這理所當然是數據訪問層的職責。我認為這個理解是對的,但是只對了一半!之所以這么說,是因為“增刪改查”有兩個層次含義。
第一個層次,是數據訪問層次上的。在這個層次上,“增刪改查”只是單純的數據庫操作,“增刪改查”可以理解為“插入一條記錄,刪除一條記錄,更新一條記錄的信息,獲取一條或多條記錄”四個操作,其意義和著眼點完全是數據訪問層面上的,不帶有任何業務成分和業務知覺。這個層面上的CRUD應該屬于數據訪問層的職責。
第二個層次,是業務邏輯層次上的。在這個層次上,“增刪改查”是業務領域內實體的變化以及一系列相關反應,“增刪改查”可以理解為“領域內新增一個業務實體,領域內去掉一個業務實體,領域內一個業務實體更新了信息,得到領域內一個或多個業務實體的信息”。
兩者最大的不同,是業務層面上的增刪改查往往不是單純的增加減少,還包括實體變化后相關的業務流程。下面舉個例子:
“添加一個新的訂單”——這是一條典型的“增”操作。在數據訪問層面上,它的意義是“在表示訂單的數據表里增加一條記錄”;而在業務邏輯層面上,它的意義除了“領域內多了一個訂單實體”外,還可能包括“根據業務規則判斷是否是重復下單,根據金額對下訂單客戶的等級做相應提升、發送Email和短信通知客戶等”。可以看到,業務層面上的“增”可能不僅是簡單封裝一個簡單的插入記錄,可能還要去做其他數據訪問——提升用戶等級,以及做一些非CRUD的業務操作——發送短信通知。
在許多稍微復雜的系統中,業務往往不僅僅是封裝了一條數據訪問操作,而是還有很多如計算等業務處理,一個業務操作期間可能要多次使用數據訪問操作。退一步說,即使某個業務僅僅封裝了一條數據訪問操作,其意義和層面也是不同的,在數據訪問層面,僅僅是多了一條記錄,而業務邏輯層面,是領域內多了一個業務實體。也許其本質上都是往數據庫插入一條記錄,但人類的抽象思維可以將之在不同層面上區分,這也是人類思維層面的一種抽象能力的表現。例如,我們知道太陽升起不過是地球自轉使得從背陰面轉到了向陽面,但當人們看日出時,很少有人會說“看!我們從背陰面轉到向陽面了!”,我們會說“看!日出!”,這就是同一事物的不同層次表現。
2.3.4、存儲過程
也許是性能上的誘惑,許多人喜歡在數據庫系統中寫很復雜的存儲過程。這樣,許多業務操作就被寫到存儲過程中去了。我個人建議,除非對性能要求極高,否則最好還是不要用存儲過程實現業務。例如,在一般的系統中,某個業務操作可能需要1秒,而是用了存儲過程只用0.1秒,看上去存儲過程將效率提高了10倍。但對大多數用戶來說,1秒和0.1秒的差別并不大,但是這樣做的話,業務會變得十分不容易維護。所以,我個人覺得,除非十分必要,還是不要用存儲過程實現業務。
后篇:http://kb.cnblogs.com/page/50527
作者:T2噬菌體出處:http://leoo2sk.cnblogs.com
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
it知識庫:細說業務邏輯(前篇),轉載需保留來源!
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。