而面向接口編程可以使我們避免這種問題。我們不再依賴于千千萬萬個PartnerAccess或者什么別的Access類,而是依賴一個IDataAccess的接口。這樣,所有的數(shù)據(jù)存取都被標準化,我們的調(diào)用代碼便的更簡單,不會依賴任何數(shù)據(jù)庫的結(jié)構(gòu),甚至不需要知道表的名字,有多少個字段等等。當我們增加一個OrderAccess類時,只需在數(shù)據(jù)存取層增加一個文件,一個類好了,而不需要更改業(yè)務(wù)邏輯層的任何代碼。
記住這個原則吧,它也可以說是面向?qū)ο蟮暮诵乃枷。會讓你受益匪淺的!
3. 領(lǐng)域模型不清晰
從上面的圖中可以看出來,本系統(tǒng)同時使用了兩種領(lǐng)域模型,一種是業(yè)務(wù)對象(Business Object),一種是強類型DataSet(Strong Type DataSet),并且在每個層次中都使用了。
舉個簡單的例子:強類型DataSet被應(yīng)用到ASP.NET的控件綁定上,用來顯示數(shù)據(jù)。而業(yè)務(wù)對象被WebService暴露給客戶端。
如果有人看過馬丁·福勒的那本《企業(yè)架構(gòu)模式》的話,應(yīng)該會記得對領(lǐng)域模型的選擇上有幾種方案。其中業(yè)務(wù)對象和強類型DataSet都被提到了,并且說明了什么時候適用哪個模型。這里我不多說,感興趣的朋友可以去看看那本書。
我想說的是,這里使用了兩個模型并存的方案。這樣使得系統(tǒng)的領(lǐng)域模型不清晰,而且存在很多的冗余,例如出現(xiàn)了Partner業(yè)務(wù)對象和PartnerDS強類型DataSet并存的現(xiàn)象,盡管他們各有各的優(yōu)缺點,但這樣勢必會造成領(lǐng)域模型的難于維護和代碼可讀性差的問題。
其實,特殊情況下,也可以兩個同時使用,但要注意,由于業(yè)務(wù)對象是屬于業(yè)務(wù)邏輯層的,而強類型DataSet是數(shù)據(jù)存取層的,所以他們都要在自己的范圍內(nèi)活動,不能被其它的層次存取。
到這里,有人可能會發(fā)現(xiàn)一個矛盾是:使用單一業(yè)務(wù)對象的話,則會對數(shù)據(jù)存取層帶來額外的開銷,因為數(shù)據(jù)存取層不能知道業(yè)務(wù)對象的存在,需要使用抽象,會帶來一些代價。但如果使用單一的強類型DataSet的話,會對業(yè)務(wù)邏輯層和展現(xiàn)層保留很多的內(nèi)部數(shù)據(jù)細節(jié),也會對系統(tǒng)架構(gòu)造成一些影響,而且也不利于WebService的傳輸。
其實,一個合格的設(shè)計師,需要對這兩種方案做各自的調(diào)整,都為自己所用,但只取他們的優(yōu)勢,而避免他們的劣勢多帶來的麻煩。
軟件設(shè)計,何嘗又不是一種取舍的藝術(shù)呢!
4. 強類型DataSet
上面講到了業(yè)務(wù)對象和強類型DataSet兩種領(lǐng)域模型的使用問題。其實強類型DataSet是.NET中很好的一種方案,它集成了數(shù)據(jù)庫和面向?qū)ο髢煞N優(yōu)點,如果使用的好的話,會事半功倍,但使用不好的話,麻煩也很大。
在本系統(tǒng)中,強類型DataSet被賦予很多使命:從數(shù)據(jù)庫中獲取信息(數(shù)據(jù)存取層)、業(yè)務(wù)處理(業(yè)務(wù)邏輯層)和數(shù)據(jù)展現(xiàn)(展現(xiàn)層),貫穿了整個系統(tǒng)。這樣使得整個系統(tǒng)對強類型DataSet的數(shù)據(jù)結(jié)構(gòu)非常依賴,一旦數(shù)據(jù)庫發(fā)生變化,所有的代碼(從數(shù)據(jù)存取到展現(xiàn)層)都要修改代碼來。并且要命的是強類型DataSet可以自動感知數(shù)據(jù)庫的變化,自動更新同步。試想,如果你是這個系統(tǒng)的編碼人員,會不會時時都提心吊膽呢?
很顯然,這是一種糟糕的設(shè)計。在分層結(jié)構(gòu)中,任何數(shù)據(jù)結(jié)構(gòu)都不能貫穿始終,特別是與數(shù)據(jù)庫結(jié)構(gòu)。這回帶來難以置信的麻煩。分層,其實是要隔離這種變化給系統(tǒng)帶來的連鎖反應(yīng)。使底層的修改不影響到頂層,反之亦然。
當然這是不是意味著強類型DataSet不能使用了呢?當然不是的。強類型DataSet是非常好的連接數(shù)據(jù)存取層和業(yè)務(wù)邏輯層的紐帶,因為它既有數(shù)據(jù)庫結(jié)構(gòu)又有對象特性。所以,只要我們能在兩個層次中各自屏蔽細節(jié),依賴于抽象而不是實現(xiàn),強類型DataSet可以在系統(tǒng)中發(fā)揮重要的作用。
5. 展現(xiàn)層太臃腫
本系統(tǒng)的很大一部分UI都是B/S的,采用ASP.NET構(gòu)建。但我發(fā)現(xiàn)很多的WebPage中包含有大量的界面邏輯和業(yè)務(wù)邏輯,基本每個WebPage的代碼都在幾百行,有點甚至上千行。試想,這樣的UI維護起來…
對于每一個開發(fā)者來說,大概都經(jīng)歷過這種痛苦,為了數(shù)據(jù)庫的一個字段的修改,要從底層到頂層,全部修改一便,而且UI的修改是麻煩的,往往是越改越煩!
其實對于UI的設(shè)計模式已經(jīng)很成熟了,大家都知道MVC模式吧。是一個很成熟,很實用的UI設(shè)計模式。另外還有MVP模式,這個是MVC的基礎(chǔ)之上提出來的,跟MVC思想相同,但細節(jié)上有所不同而已。MVC模式網(wǎng)上有很多的資料,也有很多有名的應(yīng)用案例。MVP則被廣泛應(yīng)用在微軟P&P團隊的很多項目中,諸如:Software Factory系列中都有應(yīng)用。
下面是MVC模式和MVP模式的對比:
另外,關(guān)于兩種模式的詳細對比,可以參考另一位MVP:TreeLee的文章:ASP.NET MVC Framework與WCSF中MVP模式之小小比較。