我們知道:一個(gè)軟件從無到有需要經(jīng)過如下幾個(gè)階段:分析、設(shè)計(jì)、編程、調(diào)試、部署和運(yùn)行。 編程階段我們通常使用Java/.NET這樣面向?qū)ο笳Z言工具,可以帶來很多設(shè)計(jì)上的好處,但是也存在一個(gè)奇怪的現(xiàn)象: 很多程序員雖然在使用OO語言,但是卻在code非OO的代碼,最終導(dǎo)致系統(tǒng)性能降低或失敗,這個(gè)現(xiàn)象在Java語言尤其 顯得突出,難怪有些人就把問題歸結(jié)于Java語言本身,睡不著覺怪床歪,又為了面子問題,說自己轉(zhuǎn)向.NET,實(shí)際上是在 回避自己的問題和弱點(diǎn)。 那么,這些人的問題和弱點(diǎn)體現(xiàn)在什么地方呢?從上面軟件生產(chǎn)過程來看,每個(gè)階段都對前面有所依賴, 在編程階段出問題,追根溯源,問題無疑出在分析和設(shè)計(jì)階段,分析設(shè)計(jì)作為一個(gè)軟件產(chǎn)生的龍頭,有著映射實(shí)際需求世界 到計(jì)算機(jī)世界這樣一個(gè)拷貝任務(wù),如何做到拷貝不走樣,是衡量映射方法好壞與否的主要判斷標(biāo)準(zhǔn)。 目前,將需求從客觀現(xiàn)實(shí)世界映射到計(jì)算機(jī)軟件世界主要有兩種方式:傳統(tǒng)數(shù)據(jù)庫分析設(shè)計(jì)和面向?qū)ο蠼? object-oriented class model), 當(dāng)前軟件主要潮流無疑是面向?qū)ο笳紦?jù)主流,雖然它可能不是唯一最好最簡單的解決方案,但是它是最普通,也是最恰當(dāng)?shù)摹?/P> 也就是說:在分析設(shè)計(jì)階段,采取圍繞什么為核心(是對象還是數(shù)據(jù)表為核心)的分析方法決定了后面編碼階段的編程特點(diǎn),如果以數(shù)據(jù)表為核心進(jìn)行分析設(shè)計(jì), 也就是根據(jù)需求首先得到數(shù)據(jù)表名和字段,然后培訓(xùn)程序員學(xué)會(huì)SQL語句如何操作這些數(shù)據(jù)表,那么程序員為實(shí)現(xiàn)數(shù)據(jù)表的前后順序操作, 必然會(huì)將代碼寫成過程式的風(fēng)格。 相反,如果分析設(shè)計(jì)首先根據(jù)需求得出對象模型(class Model),那么程序員使用對象語言,再加上框架輔助,就很順理成章走上OO編程風(fēng)格。 至于OO代碼相比傳統(tǒng)過程編碼的好處不是本文重點(diǎn),可參考J道()相關(guān)討論,擴(kuò)展性和維護(hù)性好,開發(fā)越深入開發(fā)速度越快無疑是OO系統(tǒng)主要優(yōu)點(diǎn)。 下面我們看看面向?qū)ο蟮腃lass Model和Database Model是如何來表達(dá)客觀世界的,也就是他們在表達(dá)需求上有些什么不同? 面向?qū)ο竽P?/STRONG>(Class Model) 類代表一個(gè)對象類型,類在代碼運(yùn)行階段將被創(chuàng)建為一個(gè)個(gè)對象實(shí)例, 每個(gè)類由兩個(gè)部分組成:屬性和行為,屬性通常是一些數(shù)據(jù)狀態(tài)值,也就是說:類將數(shù)據(jù)封裝隱藏在自己內(nèi)部了, 訪問這些數(shù)據(jù)屬性必須通過類公開的方法,或者接口。 別小看這樣一個(gè)小小包裝,卻決定了以后代碼的維護(hù)性和擴(kuò)展性, 打個(gè)比喻,日常生活中我們經(jīng)常用各種盒子和袋子包裝一些東西,這樣做就是為了方便這些東西的攜帶或儲(chǔ)藏,小到生活, 大到客觀世界每個(gè)地方,都是包裝分類的影子,無論大小公司都是一個(gè)封裝,行政部分單位劃分,倉庫物流更需要包裝, 我們從來不會(huì)因?yàn)橄勇闊┒辉敢庖胍粋€(gè)似乎多余的盒子或袋子,那么有什么理由不在我們賴之生存的軟件中(靠編軟件吃飯) 引入封裝概念呢? 這里可以再深入想像一下:不愿意用盒子和袋子的攜帶東西大部分是一些急脾氣的毛頭小伙子,而偏偏這些小伙子又從事 軟件工作,看來軟件的非對象化是注定的,只是一個(gè)玩笑。 類的方法行為也有多種類型,如公開 私有等,我們可以設(shè)計(jì)一些方法為公開接口,而將另外一些行為隱藏起來, 這樣一個(gè)看似簡單靈活的選擇,卻能夠應(yīng)付我們?nèi)蘸箢l繁的修改,軟件不修改就不叫軟件,軟件修改了就崩潰是業(yè)務(wù)軟件, 專業(yè)的軟件是抗修改的,而且能夠極其方便快速地被修改。這些都依靠接口公開和隱藏這樣一個(gè)簡單魔術(shù),具體各種魔術(shù)表演 可以參考GoF設(shè)計(jì)模式(http://www./designpatterns/index.htm)。 類的關(guān)系 類與類關(guān)系經(jīng)常是這樣:一個(gè)類包含一個(gè)類(構(gòu)造性structural),或者借助另外一個(gè)類達(dá)到某個(gè)功能(功能性), 在對需求建模分析中,構(gòu)造性的這種關(guān)系,也稱為關(guān)聯(lián)(Association)是我們關(guān)注重點(diǎn),當(dāng)然這種關(guān)系很顯然表達(dá)的是一種 靜態(tài)的結(jié)構(gòu),比如電腦包含屏幕,他們之間的關(guān)系就是一種關(guān)聯(lián)。 聚合(Aggregation)是一種表格式樣的關(guān)聯(lián),表示一個(gè)類包含多項(xiàng)子類,這種關(guān)系是一種整體與部分的關(guān)系。 一個(gè)汽車有四個(gè)輪子,四個(gè)輪子是汽車的部分。 組成(Composition)是一種更強(qiáng)烈的聚合關(guān)系,一個(gè)對象實(shí)際是由其子對象組成,子對象也唯一屬于父對象。 繼承也是類建模中經(jīng)常用到的關(guān)系,繼承可以將一些數(shù)據(jù)屬性抽象到父類中,避免重復(fù),如入庫單和出庫單有 很多屬性是差不多的,唯一不動(dòng)的就是入庫和出庫的行為,那么我們可以抽象一個(gè)庫單為父類,使用繼承關(guān)系分別 表達(dá)入庫單和出庫單。 在Evans DDD中,提到通過訪問聚合根來遍歷導(dǎo)航關(guān)聯(lián)對象,這樣做的好處很明顯保證了對象的從屬性,非常符合 我們?nèi)粘I钸壿嫞热?,你要得到盒子里面的東西,必須首先得到盒子,然后經(jīng)過一些準(zhǔn)備如打開盒子,才能得到 盒子里面的東西,假設(shè)一下,如果沒有這樣封裝導(dǎo)航關(guān)系,盒子和東西都是可以透明并行得到,你想得到東西就能夠 直接獲得,而不必經(jīng)過打開盒子這一關(guān),這樣的訪問方式首先怪誕,其次是不安全,如果盒子和東西放在數(shù)據(jù)表中,就會(huì)發(fā)生 這種情況。 好了,下面我們談?wù)撽P(guān)系數(shù)據(jù)表模型,以前我們樸素的分析設(shè)計(jì)都是根據(jù)需求直接建立數(shù)據(jù)表的方式來進(jìn)行的,為什么稱為樸素, 是因?yàn)槲覀兒孟裰挥袛?shù)據(jù)結(jié)構(gòu) 算法方面的知識(shí),也認(rèn)為只有這樣做才叫做軟件。 那么既然這條路能夠走出來,我們看看這個(gè)領(lǐng)域是如何映射客觀世界的。 數(shù)據(jù)表由于技術(shù)提供龐大數(shù)據(jù)存儲(chǔ)和可靠的數(shù)據(jù)訪問,正在不斷從技術(shù)領(lǐng)域走向社會(huì)領(lǐng)域,很多不懂計(jì)算機(jī)的人 也知道需要建立數(shù)據(jù)庫來管理一些事務(wù),但是不代表我們就必須圍繞數(shù)據(jù)庫的分析設(shè)計(jì)。 數(shù)據(jù)表是類似前面的“類”,也是一種表達(dá)客觀世界的基本單元,表有多列字段,表的字段是保存數(shù)據(jù)的,每個(gè)字段有數(shù)據(jù)類型。 注意,這里沒有數(shù)據(jù)的封裝和公開,表的字段是赤裸的,只要有數(shù)據(jù)庫訪問權(quán)限,任何人都可以訪問,沒有結(jié)構(gòu)層次關(guān)系, 都是扁平并列的,如果你想在數(shù)據(jù)表字段之間試圖看出客觀世界中的層次和封裝,那就錯(cuò)了,在拷貝不走樣這個(gè)條件下, 這個(gè)映射方法至少把這個(gè)信息拷貝丟了。 數(shù)據(jù)表也有一些行為,這些行為是基于實(shí)體的一些規(guī)則: 約束(Constraints) 能夠保證不同表字段之間的關(guān)系完整安全性,保證數(shù)據(jù)庫的數(shù)據(jù)安全。 觸發(fā)器(Triggers)提供了實(shí)體在修改 新增和刪除之前或之后的一些附加行為, 存儲(chǔ)過程(Database stored procedures)提供數(shù)據(jù)專有的腳本性語言,存儲(chǔ)過程象一個(gè)數(shù)學(xué)公式雖然具有抽象簡潔美學(xué),但是這種簡潔是悶葫蘆美學(xué),不是大眾美學(xué),只有公式存儲(chǔ)過程發(fā)明者自己了解精通,別人無法插手,軟件不是科學(xué),不是比誰智商高,科研水平高,軟件是人機(jī)工程,更講究集體,講究別人是否方便與你協(xié)同擴(kuò)展軟件。 數(shù)據(jù)表關(guān)系 數(shù)據(jù)表的關(guān)系主要是通過外健或?qū)iT關(guān)聯(lián)表來表達(dá)的,這種關(guān)系雖然可以反映1:1或1:N這樣關(guān)系,但是無法 表達(dá)關(guān)系的性質(zhì),是緊密組成關(guān)系式的關(guān)聯(lián),還是無關(guān)緊要的普通關(guān)系,正因?yàn)槿绱?,使用?shù)據(jù)表分析設(shè)計(jì)時(shí), 我們會(huì)有蜘蛛網(wǎng)的關(guān)系表,這些關(guān)系由于在后期無法分辨性質(zhì),無法進(jìn)行整理,增加了系統(tǒng)復(fù)雜性。 更重要的是:分析就是對一個(gè)可能陌生領(lǐng)域進(jìn)行探尋,如果使用數(shù)據(jù)表的分析設(shè)計(jì)方法,那么我們實(shí)際就是 在陌生領(lǐng)域中尋找數(shù)據(jù)表這樣一個(gè)形式,那么有可能產(chǎn)生誤判斷,將一個(gè)實(shí)則是表達(dá)關(guān)系的東東誤認(rèn)為是一個(gè)實(shí)體表, 因?yàn)殛P(guān)系表必然帶來關(guān)系,這樣,就必然產(chǎn)生蜘蛛網(wǎng)式的數(shù)據(jù)表模型,將簡單問題復(fù)雜化。 總結(jié) 因?yàn)榉椒ǖ牟煌?,軟件路線也就存在下面幾個(gè)路線:完全面向?qū)ο箢惤B肪€(J道網(wǎng)站和筆者一直致力于這種路線的推介); 一種是對象和關(guān)系數(shù)據(jù)庫混合型,還有一種就是過去的完全關(guān)系數(shù)據(jù)庫類型軟件(如Foxpro/VB/Delphi等)。需要參考完全面向?qū)ο箢惤B肪€的源碼可見http://www./jdonframework/app.htm#simple。 |
|