轉(zhuǎn)帖|其它|編輯:郝浩|2010-11-08 13:41:57.000|閱讀 602 次
概述:自從上篇發(fā)布以后,大家反饋了不少問題,因?yàn)榍捌v的東西不是很深,可能大家看完之后沒有什么感覺.本章(前篇,中篇,后篇)的主要目的其實(shí)首先是提出不好的設(shè)計(jì),然后對比的提出一個(gè)相對比較合理的分層架構(gòu),同時(shí)本篇也為后續(xù)講述架構(gòu)模式和設(shè)計(jì)模式等的文章做個(gè)鋪墊。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
前言:自從上篇發(fā)布以后,大家反饋了不少問題,因?yàn)榍捌v的東西不是很深,可能大家看完之后沒有什么感覺.本章(前篇,中篇,后篇)的主要目的其實(shí)首先是提出不好的設(shè)計(jì),然后對比的提出一個(gè)相對比較合理的分層架構(gòu),同時(shí)本篇也為后續(xù)講述架構(gòu)模式和設(shè)計(jì)模式等的文章做個(gè)鋪墊。
本篇的議題如下:
1. 闡明示例需求
2. 業(yè)務(wù)層設(shè)計(jì)
3. 服務(wù)層設(shè)計(jì)
4. 數(shù)據(jù)訪問層設(shè)計(jì)
5. 顯示層設(shè)計(jì)
6. UI層設(shè)計(jì)
1. 闡明示例需求
本篇還是用之前的電子商務(wù)網(wǎng)站中的一個(gè)簡單的場景來講述:在頁面上需要顯示產(chǎn)品的列表信息。并且根據(jù)產(chǎn)品的類型不同,計(jì)算出相應(yīng)的折扣。
在上篇中,我們已經(jīng)設(shè)計(jì)項(xiàng)目的邏輯分層。我們再來回顧下:

可能有的朋友認(rèn)為從Smart UI立刻跳到這種分層設(shè)計(jì),似乎快了些。其實(shí)也算是一個(gè)思想的跳躍吧。下面就來看看這種分層是如何解決之前Smart UI的問題的。
2. 業(yè)務(wù)層設(shè)計(jì)
記得在之前的Smart UI的例子中,程序的業(yè)務(wù)邏輯是直接寫在了ASPX頁面后面的cs代碼中的?,F(xiàn)在,采用分層的方法,我們采用了領(lǐng)域模型來組織來電子商務(wù)中的業(yè)務(wù)邏輯。
有關(guān)領(lǐng)域模型的一些東西,我們在后續(xù)的文章中會(huì)講解的。
注:領(lǐng)域模型模式被設(shè)計(jì)用來組織復(fù)雜的業(yè)務(wù)邏輯和關(guān)系。
下面的類圖就反映了我們之前的電子商務(wù)的需求中所用到的業(yè)務(wù)模型。

Product類就代表了電子商務(wù)中的每一個(gè)產(chǎn)品。
Price類將會(huì)包含可算折扣的業(yè)務(wù)邏輯,并且用策略模式來具體實(shí)現(xiàn)折扣的算法-。
在ASPPatterns.Chap3.Layerd.Model添加一個(gè)接口類:IDiscountStrategy:
這個(gè)接口就用來實(shí)現(xiàn)不同打折的策略,這是策略模式的一種應(yīng)用。這個(gè)模式允許我們在運(yùn)行的時(shí)候更改不同的算法實(shí)現(xiàn)。在本例子中,Price類將會(huì)根據(jù)不同的產(chǎn)品來實(shí)現(xiàn)不同的打折策略。在我們之前的那個(gè)Smart UI例子中,其實(shí)這個(gè)打折的算法我們已經(jīng)寫了,但是沒有分離出來,導(dǎo)致了每次加一個(gè)打折的算法的策略,程序就需要改動(dòng),重新編譯,部署。也就是說打折的部分是個(gè)變化點(diǎn),我們應(yīng)該分離出來的。
注:策略模式:用一個(gè)類來封裝一個(gè)算法的實(shí)現(xiàn),并且通過切換算法的實(shí)現(xiàn)允許在運(yùn)行時(shí)修改一個(gè)對象的行為。
在電子商務(wù)中,不是每種商品都會(huì)打折的,其實(shí)我們要實(shí)現(xiàn)的打折策略只有一種。但是如果這樣,我們在寫代碼的時(shí)候就要if-else判斷是否是打折的商品,其實(shí)這里還是暴露了變化點(diǎn)的:如果國慶那天,所有的商品都打折了,那么我們就得修改代碼。其實(shí)我們可以這樣想想:不打折的情況也算是一種打折,其他的商品打折可能是7折,不打折的情況就是10折。
下面我們來看看Price類的實(shí)現(xiàn)。
Price類在設(shè)計(jì)中就是用了“依賴倒置原則”,因?yàn)樗鼪]有采用某一個(gè)具體的打折實(shí)現(xiàn)算法,而且依賴于接口抽象,至于之后到底會(huì)哪種的打折算法,其實(shí)是由商品的類型來決定的。
我們還是繼續(xù)的看,現(xiàn)在看看Product類。
現(xiàn)在所有的業(yè)務(wù)實(shí)體就已經(jīng)創(chuàng)建了。至于對商品是否打折,其實(shí)這是由客戶代碼來決定:根據(jù)客戶代碼傳入的商品的類型不同,然后調(diào)用不同的策略,選擇了不同的打折算法計(jì)算折扣。所以我們這里來添加一個(gè)表示商品類型的枚舉:
我們將會(huì)把選擇哪種打折的策略的邏輯寫在一個(gè)單獨(dú)的地方,也就是說:只要客戶代碼傳入相應(yīng)的參數(shù)信息,我們就自動(dòng)的創(chuàng)建一個(gè)合適的打折策略對象。很明顯,這里可以采用工廠方法來實(shí)現(xiàn),如下:
在上面的邏輯分層中,我們建立了一個(gè)Repository的類庫,其實(shí)我們就是想采用Repository模式來實(shí)現(xiàn)”持久化無關(guān)性”-----業(yè)務(wù)類完全不用管如何保存和獲取數(shù)據(jù)。而且由Repository決定數(shù)據(jù)的來源和保存的地方,可能是數(shù)據(jù)庫,也可能就是內(nèi)存,但是不管怎么,業(yè)務(wù)類是不用管這些的。所以下面用一個(gè)接口來實(shí)現(xiàn)靈活性:
如果現(xiàn)在有很多的商品,我們想知道他們的折扣價(jià)格,最簡單的方法就是遍歷他們,判斷類型,然后應(yīng)用不同的打折策略。為了更加的可讀,我們可以為商品列表建立擴(kuò)展方法,如下:
為了簡化客戶代碼的調(diào)用工作,我們提供一個(gè)類似門戶(gateway),或者是Façade的概念:把復(fù)雜的操作邏輯隱藏,留給客戶代碼一個(gè)簡單易用的API。我們這里創(chuàng)建一個(gè)Service類,如下:
只要客戶代碼(如顯示層中的代碼)直接調(diào)用上面的方法就可以了,而且商品的折扣也根據(jù)傳入的商品類型不同來計(jì)算。
3. 服務(wù)層設(shè)計(jì)
服務(wù)層就充當(dāng)應(yīng)用程序的入口的角色。有時(shí)候,可以被認(rèn)為是façade.不僅如此,因?yàn)閟ervice分為領(lǐng)域邏輯的service和門戶的service。門戶的service常常為顯示層提供強(qiáng)類型的View Model(有時(shí)也稱為Presentation Model)。 一個(gè)View Model就是給一個(gè)專門的View來使用的。在本例中,我們將會(huì)建立Product的View Model來顯示商品的信息。一般情況下,我們不要把業(yè)務(wù)類直接暴露給顯示層,這樣很容易緊耦合,所以在中間就上一個(gè)View Model,其實(shí)View Model和業(yè)務(wù)類的結(jié)構(gòu)差不多,只是View Model做了一些調(diào)整,便于最后的顯示。關(guān)于View Model詳細(xì)的,后文講述。
注:Façade模式:為內(nèi)部負(fù)責(zé)的子系統(tǒng)提供一個(gè)簡單的接口供外部訪問。
下面我們就來看看Product的View Model是如何寫的:
可以看到,其實(shí)View Model就是做了一些顯示邏輯的處理。在這里就是多加了一些字段,這些字段就是在UI的GridView中顯示用的。我們之前的Smart UI的方法中,還建立了模板列來顯示Product類中沒有的字段,其實(shí)就相當(dāng)于在UI中作了一定的顯示邏輯的處理。這里我們直接顯示ViewModel.
大家應(yīng)該很熟悉Web Service:在客戶端和服務(wù)使用請求/響應(yīng)的消息機(jī)制進(jìn)行通信的。我們這里的客戶代碼和Service也采用這種方法,因?yàn)楹苡锌赡芪覀冊诓渴鸬臅r(shí)候Service的代碼和客戶代碼(顯示層)在不同機(jī)器上。
請求的消息的結(jié)構(gòu)如下:
服務(wù)在響應(yīng)請求的時(shí)候也要定義格式,而且我們可以在響應(yīng)中加入更多的屬性來判斷這個(gè)請求是否成功。所以在下面的代碼中,我們加入了Message屬性,用來在請求失敗的時(shí)候顯示錯(cuò)誤信息,還添加了一個(gè)Success屬性用來判斷請求的狀態(tài):
還有一點(diǎn)不要忘記了:因?yàn)镻roduct和它對應(yīng)的View Model結(jié)構(gòu)不同的,而Service返回的又是ViewModel的響應(yīng),那么就需要把獲取到的Product轉(zhuǎn)換為View Model的結(jié)構(gòu)。可以把轉(zhuǎn)換的代碼寫在一個(gè)特定的地方(可以認(rèn)為是個(gè)Mapping的過程),為了閱讀的方便,我們可以為List<Product>添加擴(kuò)展方法,直接調(diào)用,如下:
最后,我們加入一個(gè)ProductService來與業(yè)務(wù)層的Service 類進(jìn)行交互,業(yè)務(wù)層的Service會(huì)返回商品列表,然后我們現(xiàn)在添加的這個(gè)ProductService會(huì)把列表轉(zhuǎn)為ProductViewModels。
大家可能覺得奇怪:為什么這里添加了兩個(gè)ProductService,之前在業(yè)務(wù)層加一個(gè),現(xiàn)在又加一個(gè),是否命名有問題或者功能重復(fù)?其實(shí)在上一篇已經(jīng)提過:有時(shí)在業(yè)務(wù)層類添加一個(gè)service層,主要是用來組織業(yè)務(wù)流程的,常常要幾個(gè)業(yè)務(wù)類組合在一起使用,這樣主要是為了簡化客戶程序(也就是調(diào)用這個(gè)業(yè)務(wù)層的代碼)的調(diào)用,實(shí)現(xiàn)類似Façade的作用。
我們現(xiàn)在添加的ProductService就是業(yè)務(wù)層中service層的客戶程序,因?yàn)槲覀冋{(diào)用了業(yè)務(wù)層的service,往往有時(shí)候,我們不想把自己系統(tǒng)的業(yè)務(wù)類的結(jié)構(gòu)直接暴露給外界,如顯示層,而且也希望提供更加符合顯示層所需的數(shù)據(jù)結(jié)構(gòu),那么我們就添加了這個(gè)ProductService,提供從業(yè)務(wù)類到ViewModel的轉(zhuǎn)換。而且在這個(gè)ProductSevice中,我們也可以實(shí)現(xiàn)一些異常處理機(jī)制,如果涉及到了分布式調(diào)用,那么我們還可以用這個(gè)ProductService類向顯示層和UI那邊隱藏分布式的信息:實(shí)現(xiàn)代理模式。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@ke049m.cn
文章轉(zhuǎn)載自:博客轉(zhuǎn)載