談談三層結構開發的理解
一、 前言
最近幾個網友在討論程序設計中的分層設計,反響非常激烈。大家對此非常感興趣,且仁者見仁,智者見智。不管怎么樣,他們的看法代表了他們對程序的理解,是他們實踐經驗的總結,是寶貴的。今天,這里我們且不評論他們的見解正確與否,這里我只談談我對分層的看法.希望能起到拋磚引玉的作用。
二、 三層架構開發簡介
a) 什么是三層
首先,談一下什么是三層架構,所謂的三層開發就是將整個業務應用劃分為表示層-業務邏輯層―數據訪問層-數據庫等,有的還要細一些,明確地將客戶端的表示層、業務邏輯訪問、和數據訪問及數據庫訪問劃分出來,十分有利于系統的開發,維護、部署和擴展。
軟件要分層,其實總結一句話,是為了實現“高內聚、低耦合”。采用“分而治之”的思想,把問題劃分開來各個解決,易于控制,易于延展,易于分配資源。

圖1.三層結構示意圖
表示層:負責直接跟用戶進行交互,一般也就是指我們的前臺,用于數據錄入,數據顯示等。它不應該做太多的工作。表示嘛,也就意味著只做與外觀顯示相關的工作。不屬于他的工作他不用管也不該管。
業務邏輯層:用于做一些有效性驗證的工作。以更好的保證程序運行的健壯性。如數據的有效性判斷。不允許為的地方是否輸入了空字符串,該輸入Email的,格式是否正確等,數據類型的合法性判斷,該是整型的地方當然不能接受字符串了,數據庫操作是否合法,如字段長度的有效性判斷。sql防注入的問題,用戶的權限的合法性判斷等,通過以上的諸多判斷以決定是否將操作繼續向后傳遞。盡量保證程序的正常運行
數據訪問層:顧名思義,就是用于專門跟數據庫進行交互。對數據的添加,刪除,修改,顯示等。需要強調的是所有的數據對象只在這一層被引用,如System.Data。SqlClient等,除數據層之外的任何地方都不應該出現這樣的應用。
ASP.NET可以使用.NET平臺快速方便的部署三層架構。ASP.NET革命性的變化是在網頁中也使用基于事件的處理,可以指定處理的后臺代碼文件,可以使用C#,VB,J#作為后臺代碼的語言。.NET中可以方便的實現組件的裝配,后臺代碼通過命名控件可以方便的使用自己定義的組件。顯示層放在ASPX頁面中,數據庫操作和邏輯層用組件來實現,這樣就很方便的實現了三層架構。
。
b) 為什么使用三層
那么我們為什么要使用分層開發呢,它有什么獨特的優勢呢?
.NET開發平臺為我們做開發提供了強大的技術支持,使我們的開發變得非常便捷,高效。通過code behind的強大支持,我們可以將頁面設計和代碼設計有效的分離,代碼編寫,頁面設計同時進行。這比古老的asp那種插入式編寫要迅速多了,Html歸aspx,代碼歸aspx.cs,看起來倒也蠻清晰的,也沒發現有什么不妥的地方
的確,光從功能實現的基礎來說我們已經做得很好了,尤其對于一個簡單的應用來說,代碼量不是很多的情況下,這種一層結構開發完全夠用了,沒有必要搞得那么復雜。但是對一個復雜的大型系統來說這樣的設計的缺陷就很嚴重了(下面會具體介紹,分層開發其實也是為大型系統服務的),。在開發過程中我們會不停把代碼到處復制,以實現一些相似的功能。同樣的代碼為什么要寫那么多次?不但使程序變得冗長,更不利于維護,一個小小的修改或許會波及很多頁面。稍微不留神就會導致異常的產生。使程序不能正常運行。最主要的面向對象的思想沒有得到絲毫的體現,打著面向對象的幌子卻依然走著面向過程的老路。
意識到這樣的問題,我開始將程序中一些公用的處理程序寫成公共方法封裝在類中,供其它程序調用。象一些功能型的代碼集合,數據庫操作,如同SqlHelper那樣對數據操作進行合理封裝,把sql語句,參數列表作為參數,在數據庫操作過程中,只要傳入相應的參數就可以完成特定的數據操作,這就是我一開始的數據訪問層,再不用每次操作數據庫時都寫那些重復性的數據庫操作代碼。在新的應用開發中,數據訪問層可以直接拿來用。面向對象的三大特性之一的封裝性在這里得到了很好的體現。似乎找到了面向對象的感覺,代碼量較以前有了很大的減少,而且修改的時候也比較方便。這下應該可以了吧?
試問一下,如果有一天數據庫供應商發生了變化,因為數據量的增加,數據庫有access變成了sql server?這下麻煩大了,原來的數據訪問層失效了,數據操作對象發生了變化,且頁面中涉及數據對象的地方也要進行修改,因為原來可能會使用OleDbDataReader對象將數據傳遞給顯示頁面,現在都得換成SqlDataReader對象,sql和access支持的數據類型也不一致,在顯示數據時進行的數據轉換可能也要進行修改。由sql向access的轉換所做的修改會更多。還有一種情況,因為某種需要,我們要把Web形式的項目改造成windows應用,這時牽涉的修改有多大呢?如果在你的aspx.cs中放了很多處理代碼,或者還有一部分代碼存在于aspx中呢windows應用中可沒有aspx阿,是不是整個系統需要重新來做了?這都是設計不合理惹的禍。再者,就是分布式的情況,現在的設計也無法做到。也就意味著,以上的設計充其量只能算小打小鬧。
不知道我的解釋是否讓你體會了到了一些一層開發模式下的缺陷了呢?你是否碰到過這樣的情況呢?幸運的是,多層開發架構的出現很有效的解決了這樣的問題。通過將程序架構進行合理的分層,將極大的提高程序的通用性。
三層中,各個層之間的分工是很明確的,面向對象嗎,就像一個公司中的部門一樣,每個部門的分工是不一樣的,是哪個部門的任務就有哪個部門完成,對應的,各個部門的維護工作也有各自完成且不會影響其它的部門,至少影響不是很大,否則就只能說明分層還不合理。各個層之間通過有效的協作來完成系統的高效運行。表示層就是用來做接受/顯示數據的工作,它要通過與其它層的協作來完成用戶的請求,在這一層不該放太多的代碼。邏輯層就是用來做數據有效性判斷的,前面已經說過了,數據層就是用來完成底層數據交互的。表示層就不該去實現邏輯層的功能,當然我們會在客戶端對用戶的輸入做一些判斷,但服務器端,驗證還要做。用戶完全可以繞過客戶端驗證不是嗎?現在我們在看上面說的問題,數據庫發生了改變,我們只需要修改數據訪問層,其它的地方我們都不用去管,這里我傾向于借助自定義數據實體來負責層與層之間的數據交互,我們把數據填充到自定義實體中,使用自定義實體的好處請參考我上面的兩篇關于自定義實體的介紹的文章。通過數據訪問層來完全封裝數據供應商,使數據訪問層對其它層完全透明,這樣將數據庫改變帶來的修改完全限定在數據訪問層內。我們可以借助一些模式來設計一個通用的數據訪問層,這樣即使數據庫發生改變,我們只要修改一下配置就可以輕松搞定。對于開發平臺的改變也變得很容易,不管是windows還是web,變化的只是界面而已,也就是所謂的表示層,它的內核沒有變,相當于我們重作一個殼。表示層的代碼是很少的,所以修改是很有限的,其它兩層也不要修改就可以迅速做到web程序向windows程序的過渡。
你體會到三層的優勢了嗎?當然多層設計還有很多優秀的地方,我只是介紹了其中的一小部分。下面引入我所理解的三層的概念。
c) 我的三層結構。
那么怎么才能寫出一個比較好的三層結構呢?下面說說我在程序設計中采用的做法,當然這里談的只是我對三層的理解,不一定準確。歡迎拍磚。呵呵
程序設計追求的是代碼的通用性,可移植性,可維護性、功能擴展。怎么才能做到這些呢?這需要我們大量的實踐經驗做支撐。對面向對象思想的深入了解才能做到。個人覺得優秀的多層結構的設計肯定要先精通模式設計,不過遺憾的是對模式設計研究好長一段時間,依然沒能領略到它的精髓,研究模式設計真的很過癮哦。

以上是我在層序設計中所使用的分層示意圖。
Web層:也就是表示層,它負責響應用戶的請求,對于這一層越薄越好,一般不應該寫太多代碼,或者為了頁面顯示的需要做少量的代碼。大量的處理工作都交給其它的層去完成。就好比傳遞員,只負責接受,并將請求向后傳遞,具體怎么做它不用管。
Common層:這里用來封裝一些常用的功能性代碼,主要用來為其它層服務的。還有存放一些自定義實體類型和自定義實體類型集合。用于各層次之間數據交互的載體。如User,UserCollection,關于自定義實體這里就不展開了,如果系統復雜的話這一層應該比較厚實,包括下面的BLL層也是如此。
BLL層:就是邏輯層,用來對數據進行有效性驗證,牽涉到對敏感數據的操作都需要經過這里做判斷,然后才能決定操作是否合法。
Dal層:數據訪問層;封裝對數據庫的操作。我們可以做一個通用的數據訪問層,下次開發的時候,就可以直接拿過來用。很爽的。有一點從這里傳進來、傳出去的數據都用自定義實體代替,這樣就可以實現數據訪問層對其它層的完全透明。這里封裝所有于數據庫相關的代碼,包括sql語句,存儲過程等。
分層的思路說完了,在多人開發系統的過程中,就可以按層來劃分任務,只要設計的時候把接口定義好,開發人員就可以同時開發。而且不會發生沖突,做前臺的人根本就不需要知道數據庫結構是什么,該怎么去查找,更新,刪除數據,他直觀調用響應的方法就可以了。數據訪問層的人也不需要知道前臺發生了什么,定義好與其它層交互的接口,規定好參數就行。各個層都一樣,做好自己的工作就可以了,只要能做到對其它層的完全透明。這樣就可以將修改限定在一個比較小的范圍內。
但各個層具體的代碼該怎么組織,我想這就要看個人的造詣了,要開發出高性能,可擴展的代碼就需要結合模式設計的思想,通過代碼結構的科學、合理的設計方能在日后的維護過程中游刃有余。
三、 總結
1) 從開發角度和應用角度來看,三層架構比雙層或單層結構都有更大的優勢。三層結構適合群體開發,每人可以有不同的分工,協同工作使效率倍增。開發雙層或單層應用時,每個開發人員都應對系統有較深的理解,能力要求很高,開發三層應用時,則可以結合多方面的人才,只需少數人對系統全面了解,從一定程度工降低了開發的難度
2) 三層架構可以更好的支持分布式計算環境。邏輯層的應用程序可以有多個機器上運行,充分利用網絡的計算功能。分布式計算的潛力巨大,遠比升級CPU有效。美國人曾利用分式計算解密,幾個月就破解了據稱永遠都破不了的密碼
3) 也是三層架構的最大優點是它的安全性。用戶端只能通過邏輯層來訪問數據層,減少了入口點,把很多危險的系統功能都屏蔽了
最近幾個網友在討論程序設計中的分層設計,反響非常激烈。大家對此非常感興趣,且仁者見仁,智者見智。不管怎么樣,他們的看法代表了他們對程序的理解,是他們實踐經驗的總結,是寶貴的。今天,這里我們且不評論他們的見解正確與否,這里我只談談我對分層的看法.希望能起到拋磚引玉的作用。
二、 三層架構開發簡介
a) 什么是三層
首先,談一下什么是三層架構,所謂的三層開發就是將整個業務應用劃分為表示層-業務邏輯層―數據訪問層-數據庫等,有的還要細一些,明確地將客戶端的表示層、業務邏輯訪問、和數據訪問及數據庫訪問劃分出來,十分有利于系統的開發,維護、部署和擴展。
軟件要分層,其實總結一句話,是為了實現“高內聚、低耦合”。采用“分而治之”的思想,把問題劃分開來各個解決,易于控制,易于延展,易于分配資源。

圖1.三層結構示意圖
表示層:負責直接跟用戶進行交互,一般也就是指我們的前臺,用于數據錄入,數據顯示等。它不應該做太多的工作。表示嘛,也就意味著只做與外觀顯示相關的工作。不屬于他的工作他不用管也不該管。
業務邏輯層:用于做一些有效性驗證的工作。以更好的保證程序運行的健壯性。如數據的有效性判斷。不允許為的地方是否輸入了空字符串,該輸入Email的,格式是否正確等,數據類型的合法性判斷,該是整型的地方當然不能接受字符串了,數據庫操作是否合法,如字段長度的有效性判斷。sql防注入的問題,用戶的權限的合法性判斷等,通過以上的諸多判斷以決定是否將操作繼續向后傳遞。盡量保證程序的正常運行
數據訪問層:顧名思義,就是用于專門跟數據庫進行交互。對數據的添加,刪除,修改,顯示等。需要強調的是所有的數據對象只在這一層被引用,如System.Data。SqlClient等,除數據層之外的任何地方都不應該出現這樣的應用。
ASP.NET可以使用.NET平臺快速方便的部署三層架構。ASP.NET革命性的變化是在網頁中也使用基于事件的處理,可以指定處理的后臺代碼文件,可以使用C#,VB,J#作為后臺代碼的語言。.NET中可以方便的實現組件的裝配,后臺代碼通過命名控件可以方便的使用自己定義的組件。顯示層放在ASPX頁面中,數據庫操作和邏輯層用組件來實現,這樣就很方便的實現了三層架構。
。
b) 為什么使用三層
那么我們為什么要使用分層開發呢,它有什么獨特的優勢呢?
.NET開發平臺為我們做開發提供了強大的技術支持,使我們的開發變得非常便捷,高效。通過code behind的強大支持,我們可以將頁面設計和代碼設計有效的分離,代碼編寫,頁面設計同時進行。這比古老的asp那種插入式編寫要迅速多了,Html歸aspx,代碼歸aspx.cs,看起來倒也蠻清晰的,也沒發現有什么不妥的地方
的確,光從功能實現的基礎來說我們已經做得很好了,尤其對于一個簡單的應用來說,代碼量不是很多的情況下,這種一層結構開發完全夠用了,沒有必要搞得那么復雜。但是對一個復雜的大型系統來說這樣的設計的缺陷就很嚴重了(下面會具體介紹,分層開發其實也是為大型系統服務的),。在開發過程中我們會不停把代碼到處復制,以實現一些相似的功能。同樣的代碼為什么要寫那么多次?不但使程序變得冗長,更不利于維護,一個小小的修改或許會波及很多頁面。稍微不留神就會導致異常的產生。使程序不能正常運行。最主要的面向對象的思想沒有得到絲毫的體現,打著面向對象的幌子卻依然走著面向過程的老路。
意識到這樣的問題,我開始將程序中一些公用的處理程序寫成公共方法封裝在類中,供其它程序調用。象一些功能型的代碼集合,數據庫操作,如同SqlHelper那樣對數據操作進行合理封裝,把sql語句,參數列表作為參數,在數據庫操作過程中,只要傳入相應的參數就可以完成特定的數據操作,這就是我一開始的數據訪問層,再不用每次操作數據庫時都寫那些重復性的數據庫操作代碼。在新的應用開發中,數據訪問層可以直接拿來用。面向對象的三大特性之一的封裝性在這里得到了很好的體現。似乎找到了面向對象的感覺,代碼量較以前有了很大的減少,而且修改的時候也比較方便。這下應該可以了吧?
試問一下,如果有一天數據庫供應商發生了變化,因為數據量的增加,數據庫有access變成了sql server?這下麻煩大了,原來的數據訪問層失效了,數據操作對象發生了變化,且頁面中涉及數據對象的地方也要進行修改,因為原來可能會使用OleDbDataReader對象將數據傳遞給顯示頁面,現在都得換成SqlDataReader對象,sql和access支持的數據類型也不一致,在顯示數據時進行的數據轉換可能也要進行修改。由sql向access的轉換所做的修改會更多。還有一種情況,因為某種需要,我們要把Web形式的項目改造成windows應用,這時牽涉的修改有多大呢?如果在你的aspx.cs中放了很多處理代碼,或者還有一部分代碼存在于aspx中呢windows應用中可沒有aspx阿,是不是整個系統需要重新來做了?這都是設計不合理惹的禍。再者,就是分布式的情況,現在的設計也無法做到。也就意味著,以上的設計充其量只能算小打小鬧。
不知道我的解釋是否讓你體會了到了一些一層開發模式下的缺陷了呢?你是否碰到過這樣的情況呢?幸運的是,多層開發架構的出現很有效的解決了這樣的問題。通過將程序架構進行合理的分層,將極大的提高程序的通用性。
三層中,各個層之間的分工是很明確的,面向對象嗎,就像一個公司中的部門一樣,每個部門的分工是不一樣的,是哪個部門的任務就有哪個部門完成,對應的,各個部門的維護工作也有各自完成且不會影響其它的部門,至少影響不是很大,否則就只能說明分層還不合理。各個層之間通過有效的協作來完成系統的高效運行。表示層就是用來做接受/顯示數據的工作,它要通過與其它層的協作來完成用戶的請求,在這一層不該放太多的代碼。邏輯層就是用來做數據有效性判斷的,前面已經說過了,數據層就是用來完成底層數據交互的。表示層就不該去實現邏輯層的功能,當然我們會在客戶端對用戶的輸入做一些判斷,但服務器端,驗證還要做。用戶完全可以繞過客戶端驗證不是嗎?現在我們在看上面說的問題,數據庫發生了改變,我們只需要修改數據訪問層,其它的地方我們都不用去管,這里我傾向于借助自定義數據實體來負責層與層之間的數據交互,我們把數據填充到自定義實體中,使用自定義實體的好處請參考我上面的兩篇關于自定義實體的介紹的文章。通過數據訪問層來完全封裝數據供應商,使數據訪問層對其它層完全透明,這樣將數據庫改變帶來的修改完全限定在數據訪問層內。我們可以借助一些模式來設計一個通用的數據訪問層,這樣即使數據庫發生改變,我們只要修改一下配置就可以輕松搞定。對于開發平臺的改變也變得很容易,不管是windows還是web,變化的只是界面而已,也就是所謂的表示層,它的內核沒有變,相當于我們重作一個殼。表示層的代碼是很少的,所以修改是很有限的,其它兩層也不要修改就可以迅速做到web程序向windows程序的過渡。
你體會到三層的優勢了嗎?當然多層設計還有很多優秀的地方,我只是介紹了其中的一小部分。下面引入我所理解的三層的概念。
c) 我的三層結構。
那么怎么才能寫出一個比較好的三層結構呢?下面說說我在程序設計中采用的做法,當然這里談的只是我對三層的理解,不一定準確。歡迎拍磚。呵呵
程序設計追求的是代碼的通用性,可移植性,可維護性、功能擴展。怎么才能做到這些呢?這需要我們大量的實踐經驗做支撐。對面向對象思想的深入了解才能做到。個人覺得優秀的多層結構的設計肯定要先精通模式設計,不過遺憾的是對模式設計研究好長一段時間,依然沒能領略到它的精髓,研究模式設計真的很過癮哦。

以上是我在層序設計中所使用的分層示意圖。
Web層:也就是表示層,它負責響應用戶的請求,對于這一層越薄越好,一般不應該寫太多代碼,或者為了頁面顯示的需要做少量的代碼。大量的處理工作都交給其它的層去完成。就好比傳遞員,只負責接受,并將請求向后傳遞,具體怎么做它不用管。
Common層:這里用來封裝一些常用的功能性代碼,主要用來為其它層服務的。還有存放一些自定義實體類型和自定義實體類型集合。用于各層次之間數據交互的載體。如User,UserCollection,關于自定義實體這里就不展開了,如果系統復雜的話這一層應該比較厚實,包括下面的BLL層也是如此。
BLL層:就是邏輯層,用來對數據進行有效性驗證,牽涉到對敏感數據的操作都需要經過這里做判斷,然后才能決定操作是否合法。
Dal層:數據訪問層;封裝對數據庫的操作。我們可以做一個通用的數據訪問層,下次開發的時候,就可以直接拿過來用。很爽的。有一點從這里傳進來、傳出去的數據都用自定義實體代替,這樣就可以實現數據訪問層對其它層的完全透明。這里封裝所有于數據庫相關的代碼,包括sql語句,存儲過程等。
分層的思路說完了,在多人開發系統的過程中,就可以按層來劃分任務,只要設計的時候把接口定義好,開發人員就可以同時開發。而且不會發生沖突,做前臺的人根本就不需要知道數據庫結構是什么,該怎么去查找,更新,刪除數據,他直觀調用響應的方法就可以了。數據訪問層的人也不需要知道前臺發生了什么,定義好與其它層交互的接口,規定好參數就行。各個層都一樣,做好自己的工作就可以了,只要能做到對其它層的完全透明。這樣就可以將修改限定在一個比較小的范圍內。
但各個層具體的代碼該怎么組織,我想這就要看個人的造詣了,要開發出高性能,可擴展的代碼就需要結合模式設計的思想,通過代碼結構的科學、合理的設計方能在日后的維護過程中游刃有余。
三、 總結
1) 從開發角度和應用角度來看,三層架構比雙層或單層結構都有更大的優勢。三層結構適合群體開發,每人可以有不同的分工,協同工作使效率倍增。開發雙層或單層應用時,每個開發人員都應對系統有較深的理解,能力要求很高,開發三層應用時,則可以結合多方面的人才,只需少數人對系統全面了解,從一定程度工降低了開發的難度
2) 三層架構可以更好的支持分布式計算環境。邏輯層的應用程序可以有多個機器上運行,充分利用網絡的計算功能。分布式計算的潛力巨大,遠比升級CPU有效。美國人曾利用分式計算解密,幾個月就破解了據稱永遠都破不了的密碼
3) 也是三層架構的最大優點是它的安全性。用戶端只能通過邏輯層來訪問數據層,減少了入口點,把很多危險的系統功能都屏蔽了