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

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

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