還 記得97年左右開始的胖客戶機(jī)和瘦客戶機(jī)之爭(zhēng)嗎?之后又是CS和BS之爭(zhēng),然后又是兩層和多層之爭(zhēng)...,十年之后的今天我們?cè)倩剡^(guò)頭看這些爭(zhēng)論,一切似 乎看起來(lái)都那么理所應(yīng)當(dāng):程序怎么能不分層???可是再想一下,原來(lái)我們用了整整十年的時(shí)間才達(dá)成了一個(gè)程序架構(gòu)要多層的共識(shí)(效率多低?。?! 要分層,當(dāng)然基本就是三層了,其實(shí)多層的基礎(chǔ)也是三層:界面層、業(yè)務(wù)邏輯層、存儲(chǔ)層。多層只不過(guò)在三層的基礎(chǔ)上把每一層或多或少再拆分出一些來(lái)而已,總的來(lái)說(shuō)沒有什么大的變化。本系列文章中討論都以三層為基本概念。 本 文著重討論的不是如何分層和層的定義,而是在分層情況下,討論層與層之間的數(shù)據(jù)傳遞問(wèn)題。現(xiàn)在的程序很少仔細(xì)地去分析層與層之間的數(shù)據(jù)傳遞問(wèn)題,通常都是 一個(gè)對(duì)象從界面生成開始一路穿過(guò),直接保存到數(shù)據(jù)庫(kù)(最顯著的標(biāo)志當(dāng)然就是xxxID了)。這樣的做法對(duì)程序傷害很大。 首先我們從一個(gè)簡(jiǎn)單的例子開始:應(yīng)用程序的添加用戶功能。界面很簡(jiǎn)單,如下:
要 為這個(gè)界面設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)通常也很簡(jiǎn)單,class LoginInfo{ public String name; public String password; } 就好了,然后我們?cè)趂orm提交的時(shí)候new一個(gè)并且填充好LoginInfo結(jié)構(gòu),就save(loginInfo)到數(shù)據(jù)庫(kù)里邊了,最常的做法還會(huì)加 入一個(gè)int loginInfoID字段。我們把這種類似LoginInfo可以直接存儲(chǔ)到數(shù)據(jù)庫(kù)中的數(shù)據(jù)結(jié)構(gòu)命名為Persistence Object,簡(jiǎn)稱PO。嗯,看起來(lái)從頭到腳用一個(gè)數(shù)據(jù)結(jié)構(gòu)并沒有什么問(wèn)題啊! 問(wèn)題會(huì)來(lái)的,bigtall來(lái)改變一下需求,通常我們需要給用戶密碼輸入兩次,所以界面修改如下: 這 樣,form提交到服務(wù)器的數(shù)據(jù)結(jié)構(gòu)就應(yīng)該是這樣:class LoginInfo2{ public String name; public String password; public String password2; },然后服務(wù)器做的第一件事情就是比較password和password2是否相等,然后new一個(gè)LoginInfo結(jié)構(gòu),把name和 password填充到里邊,然后保存到數(shù)據(jù)庫(kù)。我們同時(shí)把LoginInfo結(jié)構(gòu)修改成這樣class LoginInfo{ public int loginInfoID; public String name; public String password; } 。 大家可以看到,隨著需求的變化,原來(lái)的“PO直通車”演化成了兩個(gè)結(jié)構(gòu),我們把LoginInfo2類似的界面層和其它層溝通的數(shù)據(jù)結(jié)構(gòu)叫做View Object,簡(jiǎn)稱VO。是不是這樣就夠了?當(dāng)然不是,我們?cè)賮?lái)修改一下需求,給系統(tǒng)加入權(quán)限功能,所以這個(gè)添加用戶實(shí)際上應(yīng)該修改成這樣: 我們需要繼續(xù)做一些改進(jìn)(或者叫做“重構(gòu)”吧),首先修改VO,同時(shí)我們把命名也規(guī)范一下:
然后把以前的LoginInfo拆分成三個(gè)類:
至此,我們順利地引出了三個(gè)概念:View Object(VO)、Business Object(BO)、Persistence Object(PO)。 他們分別是三層結(jié)構(gòu)的顯示層、業(yè)務(wù)邏輯層和存儲(chǔ)層內(nèi)部使用的數(shù)據(jù)結(jié)構(gòu),它們還有一個(gè)統(tǒng)稱,叫做數(shù)據(jù)傳輸對(duì)象Data Object(DO)。我們也可以把VO,BO和PO看成是DO在不同階段的不同表示形態(tài)。當(dāng)一個(gè)DO從顯示層開始穿越整個(gè)系統(tǒng)的時(shí)候,它的形態(tài)和結(jié)構(gòu)就 開始變化,從VO轉(zhuǎn)變到BO,最終到PO,但是這個(gè)過(guò)程不一定是可逆的,這個(gè)過(guò)程如果反向,從PO->BO->VO,很可能就對(duì)應(yīng)不同的對(duì)象 了。比如當(dāng)輸入錯(cuò)誤的時(shí)候,回饋?lái)?yè)面可能就需要增加一個(gè)錯(cuò)誤信息提示。雖然實(shí)際使用的時(shí)候,我們經(jīng)常會(huì)忽略這種細(xì)微的差異性,實(shí)際上這個(gè)錯(cuò)誤信息,只對(duì)顯 示層有意義。 DO的轉(zhuǎn)換規(guī)律一般可以總結(jié)為如下的幾個(gè)類型,實(shí)際變化則可以是各種類型的組合:
除了DO不同形態(tài)之間的轉(zhuǎn)換規(guī)律之外,不同形態(tài)內(nèi)部還有不同的工作要做:
突 然想起來(lái)有一句閑話要講。這個(gè)分析過(guò)程其實(shí)在一年前就完成了,那個(gè)時(shí)候正好沸沸揚(yáng)揚(yáng)的SOA滿天飛,當(dāng)把這個(gè)DO形態(tài)分析完畢之后,回頭看SOA發(fā)現(xiàn)它并 不屬于表現(xiàn)層,而是屬于業(yè)務(wù)邏輯層,換句話說(shuō)它使用的DO必須是BO而不是VO。而所謂的SOA也不過(guò)就是分布的業(yè)務(wù)邏輯層而已。 因?yàn)橐韵碌牟糠忠ㄙM(fèi)較多的時(shí)間查找,bigtall怕文章擱久餿了,也怕各位看官等得太久,就分兩部分發(fā)吧。下篇我們著重分析現(xiàn)net平臺(tái)和java平臺(tái)的幾個(gè)架構(gòu)在DO形態(tài)上的對(duì)比,還要談一個(gè)實(shí)用的問(wèn)題,是不是需要對(duì)象ID的問(wèn)題。 |
|
來(lái)自: rookie > 《技術(shù)帖》