概述
軟件設(shè)計(jì)是把需求轉(zhuǎn)化為軟件系統(tǒng)的最重要的環(huán)節(jié),系統(tǒng)設(shè)計(jì)的優(yōu)劣在根本上決定了軟件系統(tǒng)的質(zhì)量。
在此,主要闡述軟件系統(tǒng)設(shè)計(jì)的5個(gè)核心內(nèi)容:體系結(jié)構(gòu)設(shè)計(jì)、用戶界面設(shè)計(jì)、數(shù)據(jù)庫(kù)設(shè)計(jì)、模塊設(shè)計(jì)、數(shù)據(jù)結(jié)構(gòu)和算法設(shè)計(jì)。旨在幫助開(kāi)發(fā)人員搞清楚“設(shè)計(jì)什么”以及“如何設(shè)計(jì)”。
一般把設(shè)計(jì)過(guò)程劃分為兩個(gè)階段:概要設(shè)計(jì)階段和詳細(xì)設(shè)計(jì)階段,如下所示:
概要設(shè)計(jì)階段的重點(diǎn)是體系結(jié)構(gòu)設(shè)計(jì)。
詳細(xì)設(shè)計(jì)階段的重點(diǎn)是用戶界面設(shè)計(jì)、數(shù)據(jù)庫(kù)設(shè)計(jì)、模塊設(shè)計(jì)、數(shù)據(jù)結(jié)構(gòu)與算法設(shè)計(jì)等。
可根據(jù)項(xiàng)目的情況進(jìn)行文檔裁減和過(guò)程合并,如項(xiàng)目開(kāi)發(fā)過(guò)程只有一個(gè)設(shè)計(jì)階段和設(shè)計(jì)文檔。
體系結(jié)構(gòu)
體系結(jié)構(gòu)如同人的骨架。如果某個(gè)家伙的骨架是猴子,那么無(wú)論怎樣喂養(yǎng)和美容,這家伙始終都是猴子,不會(huì)成為人。
由此可見(jiàn),體系結(jié)構(gòu)乃是系統(tǒng)設(shè)計(jì)的重中之重。
目前業(yè)界比較流行的軟件結(jié)構(gòu)模式有C/S(客戶/服務(wù)器)、B/S(BROWSE/SERVER)、層次結(jié)構(gòu)(上下級(jí)層次結(jié)構(gòu)、順序相鄰的層次結(jié)構(gòu)、含中間件的層次結(jié)構(gòu))
體系結(jié)構(gòu)設(shè)計(jì)原則
● 合適性
即體系結(jié)構(gòu)是否適合于軟件的“功能性需求”和“非功能性需求”。高水平的設(shè)計(jì)師高就高在“設(shè)計(jì)出恰好滿足客戶需求的軟件,并且使開(kāi)發(fā)方和客戶方獲取的利益,而不是不惜代價(jià)設(shè)計(jì)出最先進(jìn)的軟件。
● 結(jié)構(gòu)穩(wěn)定性
詳細(xì)設(shè)計(jì)階段的工作如用戶界面設(shè)計(jì)、數(shù)據(jù)庫(kù)設(shè)計(jì)、模塊設(shè)計(jì)、數(shù)據(jù)結(jié)構(gòu)與算法設(shè)計(jì)等等,都是在體系結(jié)構(gòu)確定之后開(kāi)展的,而編程和測(cè)試則是更后面的工作,因此體系結(jié)構(gòu)應(yīng)在一定的時(shí)間內(nèi)保持穩(wěn)定。
軟件開(kāi)發(fā)最怕的就是需求變化,但“需求會(huì)發(fā)生變化”是個(gè)無(wú)法逃避的現(xiàn)實(shí)。人們希望在需求發(fā)生變化時(shí),只對(duì)軟件做些皮皮毛毛的修改,可千萬(wàn)別改動(dòng)軟件的體系結(jié)構(gòu)。如果當(dāng)需求發(fā)生變化時(shí),程序員不得不去修改軟件的體系結(jié)構(gòu),那么這個(gè)軟件的系統(tǒng)設(shè)計(jì)是失敗的。
高水平的設(shè)計(jì)師應(yīng)當(dāng)能夠分析需求文檔,判斷出哪些需求是穩(wěn)定不變的,哪些需求是可能變動(dòng)的。于是根據(jù)那些穩(wěn)定不變的需求設(shè)計(jì)體系結(jié)構(gòu),而根據(jù)那些可變的需求設(shè)計(jì)軟件的“可擴(kuò)展性”。
● 可擴(kuò)展性
可擴(kuò)展性是指軟件擴(kuò)展新功能的容易程度??蓴U(kuò)展性越好,表示軟件適應(yīng)“變化”的能力越強(qiáng)。
可擴(kuò)展性越來(lái)越重要,這是由現(xiàn)代軟件的商業(yè)模式?jīng)Q定的:
社會(huì)的商業(yè)越發(fā)達(dá),需求變化就越快。需求變化必將導(dǎo)致修改(或者擴(kuò)展)軟件的功能,現(xiàn)代軟件的規(guī)模和復(fù)雜性要比十年前的大得多(對(duì)比一下操作系統(tǒng)的變化就明白了),如果軟件的可擴(kuò)展性比較差的話,那么修改(或者擴(kuò)展)功能的代價(jià)會(huì)很高。
現(xiàn)代軟件產(chǎn)品通常采用“增量開(kāi)發(fā)模式”,開(kāi)發(fā)商不斷地推出軟件產(chǎn)品的新版本,從而不斷地獲取增值利潤(rùn)。如果軟件的可擴(kuò)展性比較差的話,每次開(kāi)發(fā)新版本的代價(jià)就會(huì)很高。雖然開(kāi)發(fā)商抓住了商機(jī),但卻由于設(shè)計(jì)水平差而導(dǎo)致沒(méi)有賺取多少利潤(rùn),真是要活活氣死。
● 可復(fù)用性
由經(jīng)驗(yàn)可知,通常在一個(gè)新系統(tǒng)中,大部分的內(nèi)容是成熟的,只有小部分內(nèi)容是創(chuàng)新的。一般地可以相信成熟的東西總是比較可靠的(即具有高質(zhì)量),而大量成熟的工作可以通過(guò)復(fù)用來(lái)快速實(shí)現(xiàn)(即具有高生產(chǎn)率)。
可復(fù)用性是設(shè)計(jì)出來(lái)的,而不是偶然碰到的。要使體系結(jié)構(gòu)具有良好的可復(fù)用性,設(shè)計(jì)師應(yīng)當(dāng)分析應(yīng)用域的共性問(wèn)題,然后設(shè)計(jì)出一種通用的體系結(jié)構(gòu)模式,這樣的體系結(jié)構(gòu)才可以被復(fù)用。
用戶界面設(shè)計(jì)
為了提高用戶界面的易用性和美觀程度,總結(jié)了十個(gè)設(shè)計(jì)原則。用于提高易用性的界面設(shè)計(jì)原則有8個(gè):
用戶界面適合于軟件的功能
容易理解
風(fēng)格一致
及時(shí)反饋信息
出錯(cuò)處理
適應(yīng)各種用戶
國(guó)際化
個(gè)性化
用于提高美觀程度的設(shè)計(jì)原則有:
合理的布局
和諧的色彩
● 用戶界面適合于軟件的功能
用戶界面的合適性是指界面與軟件功能相融洽的程度。軟件的功能需要通過(guò)用戶界面來(lái)展現(xiàn),用戶界面一定要適合于軟件的功能,這是最基本的要求。界面的合適性既提倡外美內(nèi)秀,又強(qiáng)調(diào)恰如其分。
● 容易理解
提高用戶界面可理解性的一些規(guī)則如下:
界面中的所有元素(如菜單、工具條等)沒(méi)有錯(cuò)誤,也不會(huì)讓人誤解。
所有的界面元素應(yīng)當(dāng)提供充分而必要的提示,例如當(dāng)鼠標(biāo)移動(dòng)到工具條上的某個(gè)圖標(biāo)按鈕時(shí),應(yīng)當(dāng)在該圖標(biāo)旁邊出現(xiàn)功能提示。
界面結(jié)構(gòu)能夠清晰地反映工作流程,以便用戶按部就班地操作。
對(duì)于復(fù)雜的用戶界面而言,提供界面“向?qū)А?,及時(shí)讓用戶知道自己在界面結(jié)構(gòu)中所處的位置。例如對(duì)于基于Web的應(yīng)用軟件,應(yīng)該在界面上顯示“當(dāng)前位置”,否則用戶很容易在眾多的頁(yè)面中迷失方向。
● 風(fēng)格一致
風(fēng)格一致有兩方面的含義:
(1) 一個(gè)軟件的用戶界面中,同類的界面元素應(yīng)當(dāng)有相同的視感和相同的操作方式。例如命令按鈕是最常見(jiàn)的界面元素,所有命令按鈕的形狀、色彩以及對(duì)鼠標(biāo)的響應(yīng)方式都是一致的。
(2) 同一類型軟件的用戶界面應(yīng)當(dāng)有一定程度的相似性。例如Microsoft公司的Office家族里有Word、Excel、PowerPoint、Outlook等軟件,這些軟件提供的“復(fù)制、剪切、粘貼”功能的操作方式都是相同的。
● 及時(shí)反饋信息
用戶進(jìn)行某項(xiàng)操作后,如果過(guò)了一會(huì)兒(幾秒鐘)用戶界面一點(diǎn)反應(yīng)都沒(méi)有,這將使用戶感到迷茫和不安,因?yàn)樗恢朗亲约翰僮麇e(cuò)了還是軟件的原因?qū)е滤罊C(jī)了。所以及時(shí)反饋信息很重要,至少要讓用戶心里有數(shù),知道該任務(wù)處理得怎么樣了,有什么樣的結(jié)果。
例如下載一個(gè)文件,界面上應(yīng)當(dāng)顯示“百分比”或相關(guān)數(shù)字來(lái)表示下載的進(jìn)度,否則人們不知道要等待多少時(shí)間。如果某些事務(wù)處理不能提供進(jìn)度等數(shù)據(jù),那么至少要給出提示信息如“正在處理,請(qǐng)等待…”,是提供合適的動(dòng)畫(huà),讓用戶明白軟件正在干活、沒(méi)有死機(jī)。
● 出錯(cuò)處理
在設(shè)計(jì)用戶界面時(shí)必須考慮出錯(cuò)處理,目的是讓用戶不必為避免犯錯(cuò)誤而提心吊膽、小心翼翼地操作。常見(jiàn)的錯(cuò)誤處理方式有:
提供對(duì)輸入數(shù)據(jù)進(jìn)行校驗(yàn)的功能。當(dāng)用戶輸入錯(cuò)誤的數(shù)據(jù)時(shí),及時(shí)提醒用戶改正數(shù)據(jù)。
對(duì)于在某些情況下不應(yīng)該使用的菜單項(xiàng)和命令按鈕,將其“失效”(屏蔽)可以有效防止該項(xiàng)功能被錯(cuò)誤地使用。例如:對(duì)于某些管理軟件,不同的用戶有不同的操作權(quán)限。如果低權(quán)限的用戶登錄到系統(tǒng),那些只有高級(jí)權(quán)限用戶才能使用的功能應(yīng)當(dāng)被屏蔽(如變成“灰色”不可操作)。
提供Undo功能,用以撤銷不期望的操作。
執(zhí)行破壞性的操作之前,應(yīng)當(dāng)獲得用戶的確認(rèn)。例如用戶刪除一個(gè)文件時(shí),應(yīng)當(dāng)彈出對(duì)話框:“真的要?jiǎng)h除該文件嗎”,當(dāng)用戶確認(rèn)后才真正刪除文件。
● 合理的布局
首先,界面的布局應(yīng)當(dāng)符合邏輯,能夠與工作流程吻合。界面設(shè)計(jì)人員只有仔細(xì)地分析軟件的需求,才能提取對(duì)界面布局有價(jià)值的信息。
其次,界面的布局應(yīng)當(dāng)整潔(整齊清爽)。界面元素應(yīng)當(dāng)在水平或者垂直方向?qū)R,行、列的間距保持一致。窗體的尺寸要合適,各種控件不能過(guò)分擁擠也不能過(guò)分寬松。要善于利用窗體和控件的空白,以及分割用的線條。
● 和諧的色彩
用戶界面是否美觀,主要取決于該界面的布局和色彩搭配。實(shí)現(xiàn)“合理的布局”相對(duì)比較容易一些,設(shè)計(jì)和諧的色彩太困難了,因?yàn)樯实慕M合千變?nèi)f化,并且人們對(duì)顏色的喜好也極不相同。
對(duì)于廣大軟件開(kāi)發(fā)人員而言,雖然我們沒(méi)有必要讓普通軟件的界面漂亮到Windows XP這種程度,但是掌握一些界面色彩的設(shè)計(jì)原則無(wú)疑是非常有益的。
如果不是為了顯示真實(shí)感的圖形和圖像,那么應(yīng)當(dāng)限制一幀屏幕的色彩數(shù)目,因?yàn)槿藗冊(cè)谟^察屏幕的時(shí)候很難同時(shí)記住多種色彩。
應(yīng)當(dāng)根據(jù)對(duì)象的重要性來(lái)選擇顏色,重要的對(duì)象應(yīng)當(dāng)用醒目的色彩表示。
使用顏色的時(shí)候應(yīng)當(dāng)保持一致性,例如錯(cuò)誤提示信息用紅色表示,正常信息用綠色表示,那么切勿篡用紅色和綠色。
在表達(dá)信息時(shí),不要過(guò)分依賴顏色,因?yàn)橛行┯脩羰巧せ蛏?。 ?shù)據(jù)庫(kù)設(shè)計(jì)
● 開(kāi)發(fā)與平臺(tái)無(wú)關(guān)的數(shù)據(jù)庫(kù)應(yīng)用程序
目前國(guó)際上應(yīng)用最廣泛的數(shù)據(jù)庫(kù)系統(tǒng)有Oracle、DB2、Informix、Sybase和SQL Server。
這些數(shù)據(jù)庫(kù)系統(tǒng)之間的激烈競(jìng)爭(zhēng)即有好處又有壞處。競(jìng)爭(zhēng)的好處是使數(shù)據(jù)庫(kù)系統(tǒng)不斷發(fā)展和完善,并且避免價(jià)格壟斷。競(jìng)爭(zhēng)的壞處是逼迫數(shù)據(jù)庫(kù)廠商不斷開(kāi)發(fā)出獨(dú)特的功能以吸引更多的用戶,所以各個(gè)數(shù)據(jù)庫(kù)系統(tǒng)的獨(dú)特功能無(wú)法形成統(tǒng)一標(biāo)準(zhǔn),導(dǎo)致用戶難以開(kāi)發(fā)出與平臺(tái)無(wú)關(guān)的數(shù)據(jù)庫(kù)應(yīng)用程序,因?yàn)橛脩艉茈y抵御數(shù)據(jù)庫(kù)系統(tǒng)獨(dú)特功能的誘惑。
讀者也許會(huì)問(wèn):“結(jié)構(gòu)化查詢語(yǔ)言(SQL)難道不是數(shù)據(jù)庫(kù)系統(tǒng)的標(biāo)準(zhǔn)嗎?”
是的,SQL是數(shù)據(jù)庫(kù)系統(tǒng)的標(biāo)準(zhǔn)查詢語(yǔ)言。可是數(shù)據(jù)庫(kù)廠商提供了太多超出SQL標(biāo)準(zhǔn)的特色功能,使人們陷入了進(jìn)退兩難的境地:
如果你想使程序與數(shù)據(jù)庫(kù)平臺(tái)無(wú)關(guān),那么只能使用SQL,放棄各個(gè)數(shù)據(jù)庫(kù)系統(tǒng)的獨(dú)特功能。
如果你超越SQL,使用了某個(gè)數(shù)據(jù)庫(kù)系統(tǒng)的獨(dú)特功能,那么這樣的程序就是與平臺(tái)相關(guān)的。
類似問(wèn)題也存在于操作系統(tǒng)、Web瀏覽器這些領(lǐng)域。理論上講,只有絕對(duì)壟斷才能形成絕對(duì)統(tǒng)一的標(biāo)準(zhǔn),但是人們既希望打破壟斷又希望有統(tǒng)一的標(biāo)準(zhǔn),這種矛盾無(wú)法徹底解決,只能折衷、妥協(xié)。建議如下:
如果你開(kāi)發(fā)的是通用的數(shù)據(jù)庫(kù)應(yīng)用軟件,不想讓?xiě)?yīng)用軟件與特定的數(shù)據(jù)庫(kù)系統(tǒng)捆綁在一起,那么你就老老實(shí)實(shí)地用SQL語(yǔ)言寫(xiě)程序。
如果你開(kāi)發(fā)的是行業(yè)專用的數(shù)據(jù)庫(kù)應(yīng)用軟件,并且這個(gè)行業(yè)已經(jīng)指定了數(shù)據(jù)庫(kù)系統(tǒng)(這種局部壟斷現(xiàn)象普遍存在),最近若干年都不會(huì)改變的話,那么你可以超越SQL使用該數(shù)據(jù)庫(kù)系統(tǒng)的獨(dú)特功能。
● 數(shù)據(jù)庫(kù)性能優(yōu)化問(wèn)題
數(shù)據(jù)庫(kù)設(shè)計(jì)的主要挑戰(zhàn)是“高速處理大容量的數(shù)據(jù)”。如何優(yōu)化數(shù)據(jù)庫(kù)的性能是設(shè)計(jì)人員經(jīng)常面臨的問(wèn)題。數(shù)據(jù)庫(kù)性能優(yōu)化主要有兩種途徑:
優(yōu)化表結(jié)構(gòu)本身。例如對(duì)第三范式的表結(jié)構(gòu)進(jìn)行反規(guī)范化處理,允許表中存在冗余數(shù)據(jù),從而減少多個(gè)表鏈接操作,達(dá)到提高性能的目的。
優(yōu)化數(shù)據(jù)庫(kù)的環(huán)境參數(shù)。例如提高硬件設(shè)施,調(diào)整表的空間盡量減少數(shù)據(jù)碎片等。
在表的物理設(shè)計(jì)階段,設(shè)計(jì)人員應(yīng)當(dāng)按照第三范式設(shè)計(jì)表結(jié)構(gòu)(即規(guī)范化處理)。這樣做的好處是:表中沒(méi)有冗余數(shù)據(jù),表結(jié)構(gòu)很清晰,將來(lái)修改或者擴(kuò)充非常方便。但是按第三范式設(shè)計(jì)也存在一些缺點(diǎn):產(chǎn)生了許多表,每個(gè)表有相對(duì)較少的列,并且這些列必須使用“主健/外健”關(guān)聯(lián)起來(lái),因此某個(gè)查詢操作可能會(huì)產(chǎn)生復(fù)雜的表鏈接,導(dǎo)致性能降低。
反規(guī)范化處理是指對(duì)第三范式的表進(jìn)行修改,通過(guò)合并一些表,或者在表中創(chuàng)建冗余的列,從而減少表鏈接操作代價(jià),達(dá)到提高性能的目的。要注意的是反規(guī)范化處理存在很大的負(fù)面影響:管理冗余數(shù)據(jù)很麻煩,如果冗余數(shù)據(jù)不同步的話,那么會(huì)發(fā)生數(shù)據(jù)錯(cuò)誤這種嚴(yán)重的問(wèn)題。
所以,對(duì)表進(jìn)行第三范式的規(guī)范化處理是第一重要的,而反規(guī)范化處理則需謹(jǐn)慎考慮、不宜過(guò)多使用?!耙?guī)范化處理”以及“反規(guī)范化處理”不是自相矛盾之舉,而是性能優(yōu)化的策略。
除了優(yōu)化表結(jié)構(gòu)之外,優(yōu)化數(shù)據(jù)庫(kù)的環(huán)境參數(shù)也能夠提高數(shù)據(jù)庫(kù)的性能。例如給服務(wù)器配置更快的CPU,增加內(nèi)存。運(yùn)行數(shù)據(jù)庫(kù)是非常消耗內(nèi)存的,內(nèi)存對(duì)數(shù)據(jù)庫(kù)性能影響比較大。由于現(xiàn)在市場(chǎng)上的內(nèi)存條越來(lái)越便宜,所以為服務(wù)器配置足夠多的內(nèi)存恐怕是成本最低、難度最低、見(jiàn)效最快的性能優(yōu)化方法。
在安裝數(shù)據(jù)庫(kù)系統(tǒng)時(shí),要為系統(tǒng)指定“塊大小”(一次物理讀寫(xiě)操作所設(shè)計(jì)的字節(jié)數(shù))。在創(chuàng)建表時(shí),也要為表指定一定的空間。如果“塊大小”和“表空間”與實(shí)際的數(shù)據(jù)存儲(chǔ)不匹配的話,那么會(huì)產(chǎn)生許多磁盤(pán)碎片,這將降低數(shù)據(jù)庫(kù)物理操作的性能。
能否有效地優(yōu)化應(yīng)用軟件數(shù)據(jù)庫(kù)的性能,主要取決于開(kāi)發(fā)者對(duì)數(shù)據(jù)庫(kù)系統(tǒng)的熟悉程度以及開(kāi)發(fā)經(jīng)驗(yàn)。
● 數(shù)據(jù)庫(kù)安全問(wèn)題
提高軟件系統(tǒng)的安全性應(yīng)當(dāng)從“管理”和“技術(shù)”兩方面著手。這里僅考慮技術(shù)手段(因?yàn)榘踩芾沓隽塑浖こ谭懂?,一般原則如下:
用戶只能用帳號(hào)登陸到應(yīng)用軟件,通過(guò)應(yīng)用軟件訪問(wèn)數(shù)據(jù)庫(kù),而沒(méi)有其它途徑可以操作數(shù)據(jù)庫(kù)。
對(duì)用戶帳號(hào)的密碼進(jìn)行加密處理,確保在任何地方都不會(huì)出現(xiàn)密碼的明文。
確定每個(gè)角色對(duì)數(shù)據(jù)庫(kù)表的操作權(quán)限,如創(chuàng)建、檢索、更新、刪除等。每個(gè)角色擁有剛好能夠完成任務(wù)的權(quán)限,不多也不少。在應(yīng)用時(shí)再為用戶分配角色,則每個(gè)用戶的權(quán)限等于他所兼角色的權(quán)限之和。
模塊設(shè)計(jì)
在設(shè)計(jì)好軟件的體系結(jié)構(gòu)后,就已經(jīng)在宏觀上明確了各個(gè)模塊應(yīng)具有什么功能,應(yīng)放在體系結(jié)構(gòu)的哪個(gè)位置。我們習(xí)慣地從功能上劃分模塊,保持“功能獨(dú)立”是模塊化設(shè)計(jì)的基本原則。因?yàn)?,“功能?dú)立”的模塊可以降低開(kāi)發(fā)、測(cè)試、維護(hù)等階段的代價(jià)。但是“功能獨(dú)立”并不意味著模塊之間保持絕對(duì)的孤立。一個(gè)系統(tǒng)要完成某項(xiàng)任務(wù),需要各個(gè)模塊相互配合才能實(shí)現(xiàn),此時(shí)模塊之間就要進(jìn)行信息交流。
評(píng)價(jià)模塊設(shè)計(jì)優(yōu)劣的三個(gè)特征因素:“信息隱藏”、“內(nèi)聚與耦合”和“封閉——開(kāi)放性”。
● 信息隱藏
為了盡量避免某個(gè)模塊的行為去干擾同一系統(tǒng)中的其它模塊,在設(shè)計(jì)模塊時(shí)就要注意信息隱藏。應(yīng)該讓模塊僅僅公開(kāi)必須要讓外界知道的內(nèi)容,而隱藏其它一切內(nèi)容。
模塊的信息隱藏可以通過(guò)接口設(shè)計(jì)來(lái)實(shí)現(xiàn)。接口是模塊的外部特征,應(yīng)當(dāng)公開(kāi);而數(shù)據(jù)結(jié)構(gòu)、算法、實(shí)現(xiàn)體等則是模塊的內(nèi)部特征,應(yīng)當(dāng)隱藏。一個(gè)模塊僅提供有限個(gè)接口(Interface),執(zhí)行模塊的功能或與模塊交流信息必須且只須通過(guò)調(diào)用公有接口來(lái)實(shí)現(xiàn)。如果模塊是一個(gè)C++對(duì)象,那么該模塊的公有接口就對(duì)應(yīng)于對(duì)象的公有函數(shù)。如果模塊是一個(gè)COM對(duì)象,那么該模塊的公有接口就是COM對(duì)象的接口。一個(gè)COM對(duì)象可以有多個(gè)接口,而每個(gè)接口實(shí)質(zhì)上是一些函數(shù)的集合。
● 高內(nèi)聚
內(nèi)聚(Cohesion)是一個(gè)模塊內(nèi)部各成分之間相關(guān)聯(lián)程度的度量。內(nèi)聚程度從低到高大致劃分為低端、中段和高端,如圖3-15所示。模塊設(shè)計(jì)者沒(méi)有必要確定內(nèi)聚的精確級(jí)別,重要的是盡量爭(zhēng)取高內(nèi)聚,避免低內(nèi)聚。
順序性內(nèi)聚 功能性內(nèi)聚
時(shí)序性內(nèi)聚 過(guò)程性內(nèi)聚 通訊性內(nèi)聚
偶然性內(nèi)聚 邏輯性內(nèi)聚
低端… 中段… 高端…
各種內(nèi)聚類型的含義如下:
偶然性內(nèi)聚。如果一個(gè)模塊的各成分之間的關(guān)系彼此松散(幾乎無(wú)關(guān)),稱為偶然性內(nèi)聚。
邏輯性內(nèi)聚。幾個(gè)邏輯上相關(guān)的功能被放在同一模塊中,則稱為邏輯性內(nèi)聚。例如一個(gè)模塊讀取各種不同類型外設(shè)的輸入。
時(shí)序性內(nèi)聚。如果一個(gè)模塊內(nèi)的幾個(gè)功能必須在同一時(shí)間內(nèi)執(zhí)行(如系統(tǒng)初始化),但這些功能只是因?yàn)闀r(shí)間因素關(guān)聯(lián)在一起,則稱為時(shí)間性內(nèi)聚。
過(guò)程性內(nèi)聚。如果一個(gè)模塊內(nèi)部的處理成分是相關(guān)的,而且這些處理必須以特定的次序執(zhí)行,則稱為過(guò)程性內(nèi)聚。
通信內(nèi)聚。如果一個(gè)模塊的所有成分都操作同一數(shù)據(jù)集或生成同一數(shù)據(jù)集,則稱為通信內(nèi)聚。
順序內(nèi)聚。如果模塊內(nèi)的某個(gè)成分的輸出作為另一個(gè)成分的輸入,則稱為順序內(nèi)聚。
功能內(nèi)聚。模塊的所有成分對(duì)于完成單一的功能都是必須的,則稱為功能內(nèi)聚。
● 低耦合
耦合(Coupling)是模塊之間依賴程度的度量。內(nèi)聚和耦合是密切相關(guān)的,與其它模塊存在強(qiáng)耦合的模塊通常意味著弱內(nèi)聚,而強(qiáng)內(nèi)聚的模塊通常意味著與其它模塊之間存在弱耦合。
耦合的強(qiáng)度依賴于以下幾個(gè)因素:(1)一個(gè)模塊對(duì)另一個(gè)模塊的函數(shù)調(diào)用數(shù)量;(2)一個(gè)模塊向另一個(gè)模塊傳遞的數(shù)據(jù)量;(3)一個(gè)模塊施加到另一個(gè)模塊的控制的多少;(4)模塊之間接口的復(fù)雜程度。
耦合程度從低到高大致劃分為低端、中段和高端,如圖3-16所示。模塊設(shè)計(jì)應(yīng)當(dāng)爭(zhēng)取“高內(nèi)聚、低耦合”,而避免“低內(nèi)聚、高耦合”。
印記耦合 控制耦合
公共耦合 內(nèi)容耦合
非直接耦合 數(shù)據(jù)耦合
低端… 中段… 高端…
各種耦合類型的含義如下:
非直接耦合。模塊之間沒(méi)有直接的信息傳遞,稱為非直接耦合。
數(shù)據(jù)耦合。模塊之間通過(guò)接口傳遞參數(shù)(數(shù)據(jù)),稱為數(shù)據(jù)耦合。
標(biāo)記耦合。模塊間通過(guò)接口傳遞內(nèi)部數(shù)據(jù)結(jié)構(gòu)的一部分(而不是簡(jiǎn)單的參數(shù)),稱為印記(Stamp)耦合。此數(shù)據(jù)結(jié)構(gòu)的變化將使相關(guān)的模塊發(fā)生變化。
控制耦合。模塊傳遞信號(hào)(如開(kāi)關(guān)值、標(biāo)志量等)給另一個(gè)模塊,接收信號(hào)的模塊根據(jù)信號(hào)值調(diào)整動(dòng)作,稱為控制耦合。
公共耦合。兩個(gè)以上的模塊共同引用一個(gè)全局?jǐn)?shù)據(jù)項(xiàng),稱為公共耦合。
內(nèi)容耦合。當(dāng)一個(gè)模塊直接修改或操作另一個(gè)模塊的數(shù)據(jù),或者直接轉(zhuǎn)入另一個(gè)模塊時(shí),就發(fā)生了內(nèi)容耦合。
數(shù)據(jù)結(jié)構(gòu)與算法設(shè)計(jì)
設(shè)計(jì)高效率的程序是基于良好的數(shù)據(jù)結(jié)構(gòu)與算法,而不是基于編程小技巧。
一般說(shuō)來(lái),數(shù)據(jù)結(jié)構(gòu)與算法就是一類數(shù)據(jù)的表示及其相關(guān)的操作(這里算法不是指數(shù)值計(jì)算的算法)。從數(shù)據(jù)表示的觀點(diǎn)來(lái)看,存儲(chǔ)在數(shù)組中的一個(gè)有序整數(shù)表也是一種數(shù)據(jù)結(jié)構(gòu)。算法是指對(duì)數(shù)據(jù)結(jié)構(gòu)施加的一些操作,例如對(duì)一個(gè)線性表進(jìn)行檢索、插入、刪除等操作。一個(gè)算法如果能在所要求的資源限制(Resource Constraints)范圍內(nèi)將問(wèn)題解決好,則稱這個(gè)算法是有效率(Efficient)的。例如一個(gè)資源限制可能是“用于存儲(chǔ)數(shù)據(jù)的內(nèi)存有限”,或者“允許執(zhí)行每個(gè)子任務(wù)所需的時(shí)間有限”。一個(gè)算法如果比其它已知算法所需要的資源都少,這個(gè)算法也被稱為是有效率的。算法的代價(jià)(Cost)是指消耗的資源量。一般說(shuō)來(lái),代價(jià)是由一個(gè)關(guān)鍵資源例如時(shí)間或空間來(lái)評(píng)估的。
毋庸置疑,人們編寫(xiě)程序是為了解決問(wèn)題。只有通過(guò)預(yù)先分析問(wèn)題來(lái)確定必須達(dá)到的性能目標(biāo),才有希望挑選出正確的數(shù)據(jù)結(jié)構(gòu)。有相當(dāng)多的程序員忽視了這一分析過(guò)程,而直接選用某一個(gè)他們習(xí)慣使用的,但是與問(wèn)題不相稱的數(shù)據(jù)結(jié)構(gòu),結(jié)果設(shè)計(jì)出一個(gè)低效率的程序。如果使用簡(jiǎn)單的設(shè)計(jì)就能夠達(dá)到性能目標(biāo)時(shí),選用復(fù)雜的數(shù)據(jù)結(jié)構(gòu)也是沒(méi)有道理的。
人們對(duì)常用的數(shù)據(jù)結(jié)構(gòu)與算法的研究已經(jīng)相當(dāng)透徹,可以歸納出一些設(shè)計(jì)原則:
1) 一種數(shù)據(jù)結(jié)構(gòu)與算法都有其時(shí)間、空間的開(kāi)銷和收益。當(dāng)面臨一個(gè)新的設(shè)計(jì)問(wèn)題時(shí),設(shè)計(jì)者要徹底地掌握怎樣權(quán)衡時(shí)空開(kāi)銷和算法有效性的方法。這就需要懂得算法分析的原理,而且還需要了解所使用的物理介質(zhì)的特性(例如,數(shù)據(jù)存儲(chǔ)在磁盤(pán)上與存儲(chǔ)在內(nèi)存中,就有不同的考慮)。
2) 開(kāi)銷和收益有關(guān)的是時(shí)間——空間的權(quán)衡。通??梢杂酶蟮臅r(shí)間開(kāi)銷來(lái)?yè)Q取空間的收益,反之亦然。時(shí)間——空間的權(quán)衡普遍地存在于軟件開(kāi)發(fā)的各個(gè)階段中。
3) 設(shè)計(jì)人員應(yīng)該充分地了解一些常用的數(shù)據(jù)結(jié)構(gòu)與算法,避免不必要的重復(fù)設(shè)計(jì)工作。
4) 數(shù)據(jù)結(jié)構(gòu)與算法為應(yīng)用服務(wù)。我們必須先了解應(yīng)用的需求,再尋找或設(shè)計(jì)與實(shí)際應(yīng)用相匹配的數(shù)據(jù)結(jié)構(gòu)。
數(shù)據(jù)結(jié)構(gòu)與算法設(shè)計(jì)的一般流程如下:
(1)數(shù)據(jù)結(jié)構(gòu)與算法有全局和局部之分,當(dāng)然先設(shè)計(jì)全局的,后設(shè)計(jì)局部的(通常在模塊設(shè)計(jì)時(shí)進(jìn)行)。
(2)根據(jù)問(wèn)題的特征,先查找已經(jīng)存在的數(shù)據(jù)結(jié)構(gòu)與算法,挑選最合適的(并不一定是最先進(jìn)的)。如果不存在現(xiàn)成的,那么自己設(shè)計(jì)。
(3)設(shè)計(jì)并且編寫(xiě)代碼之后,要進(jìn)行測(cè)試。如果不滿足性能要求,那么要進(jìn)一步優(yōu)化數(shù)據(jù)結(jié)構(gòu)和算法。
軟件設(shè)計(jì)是把需求轉(zhuǎn)化為軟件系統(tǒng)的最重要的環(huán)節(jié),系統(tǒng)設(shè)計(jì)的優(yōu)劣在根本上決定了軟件系統(tǒng)的質(zhì)量。
在此,主要闡述軟件系統(tǒng)設(shè)計(jì)的5個(gè)核心內(nèi)容:體系結(jié)構(gòu)設(shè)計(jì)、用戶界面設(shè)計(jì)、數(shù)據(jù)庫(kù)設(shè)計(jì)、模塊設(shè)計(jì)、數(shù)據(jù)結(jié)構(gòu)和算法設(shè)計(jì)。旨在幫助開(kāi)發(fā)人員搞清楚“設(shè)計(jì)什么”以及“如何設(shè)計(jì)”。
一般把設(shè)計(jì)過(guò)程劃分為兩個(gè)階段:概要設(shè)計(jì)階段和詳細(xì)設(shè)計(jì)階段,如下所示:
概要設(shè)計(jì)階段的重點(diǎn)是體系結(jié)構(gòu)設(shè)計(jì)。
詳細(xì)設(shè)計(jì)階段的重點(diǎn)是用戶界面設(shè)計(jì)、數(shù)據(jù)庫(kù)設(shè)計(jì)、模塊設(shè)計(jì)、數(shù)據(jù)結(jié)構(gòu)與算法設(shè)計(jì)等。
可根據(jù)項(xiàng)目的情況進(jìn)行文檔裁減和過(guò)程合并,如項(xiàng)目開(kāi)發(fā)過(guò)程只有一個(gè)設(shè)計(jì)階段和設(shè)計(jì)文檔。
體系結(jié)構(gòu)
體系結(jié)構(gòu)如同人的骨架。如果某個(gè)家伙的骨架是猴子,那么無(wú)論怎樣喂養(yǎng)和美容,這家伙始終都是猴子,不會(huì)成為人。
由此可見(jiàn),體系結(jié)構(gòu)乃是系統(tǒng)設(shè)計(jì)的重中之重。
目前業(yè)界比較流行的軟件結(jié)構(gòu)模式有C/S(客戶/服務(wù)器)、B/S(BROWSE/SERVER)、層次結(jié)構(gòu)(上下級(jí)層次結(jié)構(gòu)、順序相鄰的層次結(jié)構(gòu)、含中間件的層次結(jié)構(gòu))
體系結(jié)構(gòu)設(shè)計(jì)原則
● 合適性
即體系結(jié)構(gòu)是否適合于軟件的“功能性需求”和“非功能性需求”。高水平的設(shè)計(jì)師高就高在“設(shè)計(jì)出恰好滿足客戶需求的軟件,并且使開(kāi)發(fā)方和客戶方獲取的利益,而不是不惜代價(jià)設(shè)計(jì)出最先進(jìn)的軟件。
● 結(jié)構(gòu)穩(wěn)定性
詳細(xì)設(shè)計(jì)階段的工作如用戶界面設(shè)計(jì)、數(shù)據(jù)庫(kù)設(shè)計(jì)、模塊設(shè)計(jì)、數(shù)據(jù)結(jié)構(gòu)與算法設(shè)計(jì)等等,都是在體系結(jié)構(gòu)確定之后開(kāi)展的,而編程和測(cè)試則是更后面的工作,因此體系結(jié)構(gòu)應(yīng)在一定的時(shí)間內(nèi)保持穩(wěn)定。
軟件開(kāi)發(fā)最怕的就是需求變化,但“需求會(huì)發(fā)生變化”是個(gè)無(wú)法逃避的現(xiàn)實(shí)。人們希望在需求發(fā)生變化時(shí),只對(duì)軟件做些皮皮毛毛的修改,可千萬(wàn)別改動(dòng)軟件的體系結(jié)構(gòu)。如果當(dāng)需求發(fā)生變化時(shí),程序員不得不去修改軟件的體系結(jié)構(gòu),那么這個(gè)軟件的系統(tǒng)設(shè)計(jì)是失敗的。
高水平的設(shè)計(jì)師應(yīng)當(dāng)能夠分析需求文檔,判斷出哪些需求是穩(wěn)定不變的,哪些需求是可能變動(dòng)的。于是根據(jù)那些穩(wěn)定不變的需求設(shè)計(jì)體系結(jié)構(gòu),而根據(jù)那些可變的需求設(shè)計(jì)軟件的“可擴(kuò)展性”。
● 可擴(kuò)展性
可擴(kuò)展性是指軟件擴(kuò)展新功能的容易程度??蓴U(kuò)展性越好,表示軟件適應(yīng)“變化”的能力越強(qiáng)。
可擴(kuò)展性越來(lái)越重要,這是由現(xiàn)代軟件的商業(yè)模式?jīng)Q定的:
社會(huì)的商業(yè)越發(fā)達(dá),需求變化就越快。需求變化必將導(dǎo)致修改(或者擴(kuò)展)軟件的功能,現(xiàn)代軟件的規(guī)模和復(fù)雜性要比十年前的大得多(對(duì)比一下操作系統(tǒng)的變化就明白了),如果軟件的可擴(kuò)展性比較差的話,那么修改(或者擴(kuò)展)功能的代價(jià)會(huì)很高。
現(xiàn)代軟件產(chǎn)品通常采用“增量開(kāi)發(fā)模式”,開(kāi)發(fā)商不斷地推出軟件產(chǎn)品的新版本,從而不斷地獲取增值利潤(rùn)。如果軟件的可擴(kuò)展性比較差的話,每次開(kāi)發(fā)新版本的代價(jià)就會(huì)很高。雖然開(kāi)發(fā)商抓住了商機(jī),但卻由于設(shè)計(jì)水平差而導(dǎo)致沒(méi)有賺取多少利潤(rùn),真是要活活氣死。
● 可復(fù)用性
由經(jīng)驗(yàn)可知,通常在一個(gè)新系統(tǒng)中,大部分的內(nèi)容是成熟的,只有小部分內(nèi)容是創(chuàng)新的。一般地可以相信成熟的東西總是比較可靠的(即具有高質(zhì)量),而大量成熟的工作可以通過(guò)復(fù)用來(lái)快速實(shí)現(xiàn)(即具有高生產(chǎn)率)。
可復(fù)用性是設(shè)計(jì)出來(lái)的,而不是偶然碰到的。要使體系結(jié)構(gòu)具有良好的可復(fù)用性,設(shè)計(jì)師應(yīng)當(dāng)分析應(yīng)用域的共性問(wèn)題,然后設(shè)計(jì)出一種通用的體系結(jié)構(gòu)模式,這樣的體系結(jié)構(gòu)才可以被復(fù)用。
用戶界面設(shè)計(jì)
為了提高用戶界面的易用性和美觀程度,總結(jié)了十個(gè)設(shè)計(jì)原則。用于提高易用性的界面設(shè)計(jì)原則有8個(gè):
用戶界面適合于軟件的功能
容易理解
風(fēng)格一致
及時(shí)反饋信息
出錯(cuò)處理
適應(yīng)各種用戶
國(guó)際化
個(gè)性化
用于提高美觀程度的設(shè)計(jì)原則有:
合理的布局
和諧的色彩
● 用戶界面適合于軟件的功能
用戶界面的合適性是指界面與軟件功能相融洽的程度。軟件的功能需要通過(guò)用戶界面來(lái)展現(xiàn),用戶界面一定要適合于軟件的功能,這是最基本的要求。界面的合適性既提倡外美內(nèi)秀,又強(qiáng)調(diào)恰如其分。
● 容易理解
提高用戶界面可理解性的一些規(guī)則如下:
界面中的所有元素(如菜單、工具條等)沒(méi)有錯(cuò)誤,也不會(huì)讓人誤解。
所有的界面元素應(yīng)當(dāng)提供充分而必要的提示,例如當(dāng)鼠標(biāo)移動(dòng)到工具條上的某個(gè)圖標(biāo)按鈕時(shí),應(yīng)當(dāng)在該圖標(biāo)旁邊出現(xiàn)功能提示。
界面結(jié)構(gòu)能夠清晰地反映工作流程,以便用戶按部就班地操作。
對(duì)于復(fù)雜的用戶界面而言,提供界面“向?qū)А?,及時(shí)讓用戶知道自己在界面結(jié)構(gòu)中所處的位置。例如對(duì)于基于Web的應(yīng)用軟件,應(yīng)該在界面上顯示“當(dāng)前位置”,否則用戶很容易在眾多的頁(yè)面中迷失方向。
● 風(fēng)格一致
風(fēng)格一致有兩方面的含義:
(1) 一個(gè)軟件的用戶界面中,同類的界面元素應(yīng)當(dāng)有相同的視感和相同的操作方式。例如命令按鈕是最常見(jiàn)的界面元素,所有命令按鈕的形狀、色彩以及對(duì)鼠標(biāo)的響應(yīng)方式都是一致的。
(2) 同一類型軟件的用戶界面應(yīng)當(dāng)有一定程度的相似性。例如Microsoft公司的Office家族里有Word、Excel、PowerPoint、Outlook等軟件,這些軟件提供的“復(fù)制、剪切、粘貼”功能的操作方式都是相同的。
● 及時(shí)反饋信息
用戶進(jìn)行某項(xiàng)操作后,如果過(guò)了一會(huì)兒(幾秒鐘)用戶界面一點(diǎn)反應(yīng)都沒(méi)有,這將使用戶感到迷茫和不安,因?yàn)樗恢朗亲约翰僮麇e(cuò)了還是軟件的原因?qū)е滤罊C(jī)了。所以及時(shí)反饋信息很重要,至少要讓用戶心里有數(shù),知道該任務(wù)處理得怎么樣了,有什么樣的結(jié)果。
例如下載一個(gè)文件,界面上應(yīng)當(dāng)顯示“百分比”或相關(guān)數(shù)字來(lái)表示下載的進(jìn)度,否則人們不知道要等待多少時(shí)間。如果某些事務(wù)處理不能提供進(jìn)度等數(shù)據(jù),那么至少要給出提示信息如“正在處理,請(qǐng)等待…”,是提供合適的動(dòng)畫(huà),讓用戶明白軟件正在干活、沒(méi)有死機(jī)。
● 出錯(cuò)處理
在設(shè)計(jì)用戶界面時(shí)必須考慮出錯(cuò)處理,目的是讓用戶不必為避免犯錯(cuò)誤而提心吊膽、小心翼翼地操作。常見(jiàn)的錯(cuò)誤處理方式有:
提供對(duì)輸入數(shù)據(jù)進(jìn)行校驗(yàn)的功能。當(dāng)用戶輸入錯(cuò)誤的數(shù)據(jù)時(shí),及時(shí)提醒用戶改正數(shù)據(jù)。
對(duì)于在某些情況下不應(yīng)該使用的菜單項(xiàng)和命令按鈕,將其“失效”(屏蔽)可以有效防止該項(xiàng)功能被錯(cuò)誤地使用。例如:對(duì)于某些管理軟件,不同的用戶有不同的操作權(quán)限。如果低權(quán)限的用戶登錄到系統(tǒng),那些只有高級(jí)權(quán)限用戶才能使用的功能應(yīng)當(dāng)被屏蔽(如變成“灰色”不可操作)。
提供Undo功能,用以撤銷不期望的操作。
執(zhí)行破壞性的操作之前,應(yīng)當(dāng)獲得用戶的確認(rèn)。例如用戶刪除一個(gè)文件時(shí),應(yīng)當(dāng)彈出對(duì)話框:“真的要?jiǎng)h除該文件嗎”,當(dāng)用戶確認(rèn)后才真正刪除文件。
● 合理的布局
首先,界面的布局應(yīng)當(dāng)符合邏輯,能夠與工作流程吻合。界面設(shè)計(jì)人員只有仔細(xì)地分析軟件的需求,才能提取對(duì)界面布局有價(jià)值的信息。
其次,界面的布局應(yīng)當(dāng)整潔(整齊清爽)。界面元素應(yīng)當(dāng)在水平或者垂直方向?qū)R,行、列的間距保持一致。窗體的尺寸要合適,各種控件不能過(guò)分擁擠也不能過(guò)分寬松。要善于利用窗體和控件的空白,以及分割用的線條。
● 和諧的色彩
用戶界面是否美觀,主要取決于該界面的布局和色彩搭配。實(shí)現(xiàn)“合理的布局”相對(duì)比較容易一些,設(shè)計(jì)和諧的色彩太困難了,因?yàn)樯实慕M合千變?nèi)f化,并且人們對(duì)顏色的喜好也極不相同。
對(duì)于廣大軟件開(kāi)發(fā)人員而言,雖然我們沒(méi)有必要讓普通軟件的界面漂亮到Windows XP這種程度,但是掌握一些界面色彩的設(shè)計(jì)原則無(wú)疑是非常有益的。
如果不是為了顯示真實(shí)感的圖形和圖像,那么應(yīng)當(dāng)限制一幀屏幕的色彩數(shù)目,因?yàn)槿藗冊(cè)谟^察屏幕的時(shí)候很難同時(shí)記住多種色彩。
應(yīng)當(dāng)根據(jù)對(duì)象的重要性來(lái)選擇顏色,重要的對(duì)象應(yīng)當(dāng)用醒目的色彩表示。
使用顏色的時(shí)候應(yīng)當(dāng)保持一致性,例如錯(cuò)誤提示信息用紅色表示,正常信息用綠色表示,那么切勿篡用紅色和綠色。
在表達(dá)信息時(shí),不要過(guò)分依賴顏色,因?yàn)橛行┯脩羰巧せ蛏?。 ?shù)據(jù)庫(kù)設(shè)計(jì)
● 開(kāi)發(fā)與平臺(tái)無(wú)關(guān)的數(shù)據(jù)庫(kù)應(yīng)用程序
目前國(guó)際上應(yīng)用最廣泛的數(shù)據(jù)庫(kù)系統(tǒng)有Oracle、DB2、Informix、Sybase和SQL Server。
這些數(shù)據(jù)庫(kù)系統(tǒng)之間的激烈競(jìng)爭(zhēng)即有好處又有壞處。競(jìng)爭(zhēng)的好處是使數(shù)據(jù)庫(kù)系統(tǒng)不斷發(fā)展和完善,并且避免價(jià)格壟斷。競(jìng)爭(zhēng)的壞處是逼迫數(shù)據(jù)庫(kù)廠商不斷開(kāi)發(fā)出獨(dú)特的功能以吸引更多的用戶,所以各個(gè)數(shù)據(jù)庫(kù)系統(tǒng)的獨(dú)特功能無(wú)法形成統(tǒng)一標(biāo)準(zhǔn),導(dǎo)致用戶難以開(kāi)發(fā)出與平臺(tái)無(wú)關(guān)的數(shù)據(jù)庫(kù)應(yīng)用程序,因?yàn)橛脩艉茈y抵御數(shù)據(jù)庫(kù)系統(tǒng)獨(dú)特功能的誘惑。
讀者也許會(huì)問(wèn):“結(jié)構(gòu)化查詢語(yǔ)言(SQL)難道不是數(shù)據(jù)庫(kù)系統(tǒng)的標(biāo)準(zhǔn)嗎?”
是的,SQL是數(shù)據(jù)庫(kù)系統(tǒng)的標(biāo)準(zhǔn)查詢語(yǔ)言。可是數(shù)據(jù)庫(kù)廠商提供了太多超出SQL標(biāo)準(zhǔn)的特色功能,使人們陷入了進(jìn)退兩難的境地:
如果你想使程序與數(shù)據(jù)庫(kù)平臺(tái)無(wú)關(guān),那么只能使用SQL,放棄各個(gè)數(shù)據(jù)庫(kù)系統(tǒng)的獨(dú)特功能。
如果你超越SQL,使用了某個(gè)數(shù)據(jù)庫(kù)系統(tǒng)的獨(dú)特功能,那么這樣的程序就是與平臺(tái)相關(guān)的。
類似問(wèn)題也存在于操作系統(tǒng)、Web瀏覽器這些領(lǐng)域。理論上講,只有絕對(duì)壟斷才能形成絕對(duì)統(tǒng)一的標(biāo)準(zhǔn),但是人們既希望打破壟斷又希望有統(tǒng)一的標(biāo)準(zhǔn),這種矛盾無(wú)法徹底解決,只能折衷、妥協(xié)。建議如下:
如果你開(kāi)發(fā)的是通用的數(shù)據(jù)庫(kù)應(yīng)用軟件,不想讓?xiě)?yīng)用軟件與特定的數(shù)據(jù)庫(kù)系統(tǒng)捆綁在一起,那么你就老老實(shí)實(shí)地用SQL語(yǔ)言寫(xiě)程序。
如果你開(kāi)發(fā)的是行業(yè)專用的數(shù)據(jù)庫(kù)應(yīng)用軟件,并且這個(gè)行業(yè)已經(jīng)指定了數(shù)據(jù)庫(kù)系統(tǒng)(這種局部壟斷現(xiàn)象普遍存在),最近若干年都不會(huì)改變的話,那么你可以超越SQL使用該數(shù)據(jù)庫(kù)系統(tǒng)的獨(dú)特功能。
● 數(shù)據(jù)庫(kù)性能優(yōu)化問(wèn)題
數(shù)據(jù)庫(kù)設(shè)計(jì)的主要挑戰(zhàn)是“高速處理大容量的數(shù)據(jù)”。如何優(yōu)化數(shù)據(jù)庫(kù)的性能是設(shè)計(jì)人員經(jīng)常面臨的問(wèn)題。數(shù)據(jù)庫(kù)性能優(yōu)化主要有兩種途徑:
優(yōu)化表結(jié)構(gòu)本身。例如對(duì)第三范式的表結(jié)構(gòu)進(jìn)行反規(guī)范化處理,允許表中存在冗余數(shù)據(jù),從而減少多個(gè)表鏈接操作,達(dá)到提高性能的目的。
優(yōu)化數(shù)據(jù)庫(kù)的環(huán)境參數(shù)。例如提高硬件設(shè)施,調(diào)整表的空間盡量減少數(shù)據(jù)碎片等。
在表的物理設(shè)計(jì)階段,設(shè)計(jì)人員應(yīng)當(dāng)按照第三范式設(shè)計(jì)表結(jié)構(gòu)(即規(guī)范化處理)。這樣做的好處是:表中沒(méi)有冗余數(shù)據(jù),表結(jié)構(gòu)很清晰,將來(lái)修改或者擴(kuò)充非常方便。但是按第三范式設(shè)計(jì)也存在一些缺點(diǎn):產(chǎn)生了許多表,每個(gè)表有相對(duì)較少的列,并且這些列必須使用“主健/外健”關(guān)聯(lián)起來(lái),因此某個(gè)查詢操作可能會(huì)產(chǎn)生復(fù)雜的表鏈接,導(dǎo)致性能降低。
反規(guī)范化處理是指對(duì)第三范式的表進(jìn)行修改,通過(guò)合并一些表,或者在表中創(chuàng)建冗余的列,從而減少表鏈接操作代價(jià),達(dá)到提高性能的目的。要注意的是反規(guī)范化處理存在很大的負(fù)面影響:管理冗余數(shù)據(jù)很麻煩,如果冗余數(shù)據(jù)不同步的話,那么會(huì)發(fā)生數(shù)據(jù)錯(cuò)誤這種嚴(yán)重的問(wèn)題。
所以,對(duì)表進(jìn)行第三范式的規(guī)范化處理是第一重要的,而反規(guī)范化處理則需謹(jǐn)慎考慮、不宜過(guò)多使用?!耙?guī)范化處理”以及“反規(guī)范化處理”不是自相矛盾之舉,而是性能優(yōu)化的策略。
除了優(yōu)化表結(jié)構(gòu)之外,優(yōu)化數(shù)據(jù)庫(kù)的環(huán)境參數(shù)也能夠提高數(shù)據(jù)庫(kù)的性能。例如給服務(wù)器配置更快的CPU,增加內(nèi)存。運(yùn)行數(shù)據(jù)庫(kù)是非常消耗內(nèi)存的,內(nèi)存對(duì)數(shù)據(jù)庫(kù)性能影響比較大。由于現(xiàn)在市場(chǎng)上的內(nèi)存條越來(lái)越便宜,所以為服務(wù)器配置足夠多的內(nèi)存恐怕是成本最低、難度最低、見(jiàn)效最快的性能優(yōu)化方法。
在安裝數(shù)據(jù)庫(kù)系統(tǒng)時(shí),要為系統(tǒng)指定“塊大小”(一次物理讀寫(xiě)操作所設(shè)計(jì)的字節(jié)數(shù))。在創(chuàng)建表時(shí),也要為表指定一定的空間。如果“塊大小”和“表空間”與實(shí)際的數(shù)據(jù)存儲(chǔ)不匹配的話,那么會(huì)產(chǎn)生許多磁盤(pán)碎片,這將降低數(shù)據(jù)庫(kù)物理操作的性能。
能否有效地優(yōu)化應(yīng)用軟件數(shù)據(jù)庫(kù)的性能,主要取決于開(kāi)發(fā)者對(duì)數(shù)據(jù)庫(kù)系統(tǒng)的熟悉程度以及開(kāi)發(fā)經(jīng)驗(yàn)。
● 數(shù)據(jù)庫(kù)安全問(wèn)題
提高軟件系統(tǒng)的安全性應(yīng)當(dāng)從“管理”和“技術(shù)”兩方面著手。這里僅考慮技術(shù)手段(因?yàn)榘踩芾沓隽塑浖こ谭懂?,一般原則如下:
用戶只能用帳號(hào)登陸到應(yīng)用軟件,通過(guò)應(yīng)用軟件訪問(wèn)數(shù)據(jù)庫(kù),而沒(méi)有其它途徑可以操作數(shù)據(jù)庫(kù)。
對(duì)用戶帳號(hào)的密碼進(jìn)行加密處理,確保在任何地方都不會(huì)出現(xiàn)密碼的明文。
確定每個(gè)角色對(duì)數(shù)據(jù)庫(kù)表的操作權(quán)限,如創(chuàng)建、檢索、更新、刪除等。每個(gè)角色擁有剛好能夠完成任務(wù)的權(quán)限,不多也不少。在應(yīng)用時(shí)再為用戶分配角色,則每個(gè)用戶的權(quán)限等于他所兼角色的權(quán)限之和。
模塊設(shè)計(jì)
在設(shè)計(jì)好軟件的體系結(jié)構(gòu)后,就已經(jīng)在宏觀上明確了各個(gè)模塊應(yīng)具有什么功能,應(yīng)放在體系結(jié)構(gòu)的哪個(gè)位置。我們習(xí)慣地從功能上劃分模塊,保持“功能獨(dú)立”是模塊化設(shè)計(jì)的基本原則。因?yàn)?,“功能?dú)立”的模塊可以降低開(kāi)發(fā)、測(cè)試、維護(hù)等階段的代價(jià)。但是“功能獨(dú)立”并不意味著模塊之間保持絕對(duì)的孤立。一個(gè)系統(tǒng)要完成某項(xiàng)任務(wù),需要各個(gè)模塊相互配合才能實(shí)現(xiàn),此時(shí)模塊之間就要進(jìn)行信息交流。
評(píng)價(jià)模塊設(shè)計(jì)優(yōu)劣的三個(gè)特征因素:“信息隱藏”、“內(nèi)聚與耦合”和“封閉——開(kāi)放性”。
● 信息隱藏
為了盡量避免某個(gè)模塊的行為去干擾同一系統(tǒng)中的其它模塊,在設(shè)計(jì)模塊時(shí)就要注意信息隱藏。應(yīng)該讓模塊僅僅公開(kāi)必須要讓外界知道的內(nèi)容,而隱藏其它一切內(nèi)容。
模塊的信息隱藏可以通過(guò)接口設(shè)計(jì)來(lái)實(shí)現(xiàn)。接口是模塊的外部特征,應(yīng)當(dāng)公開(kāi);而數(shù)據(jù)結(jié)構(gòu)、算法、實(shí)現(xiàn)體等則是模塊的內(nèi)部特征,應(yīng)當(dāng)隱藏。一個(gè)模塊僅提供有限個(gè)接口(Interface),執(zhí)行模塊的功能或與模塊交流信息必須且只須通過(guò)調(diào)用公有接口來(lái)實(shí)現(xiàn)。如果模塊是一個(gè)C++對(duì)象,那么該模塊的公有接口就對(duì)應(yīng)于對(duì)象的公有函數(shù)。如果模塊是一個(gè)COM對(duì)象,那么該模塊的公有接口就是COM對(duì)象的接口。一個(gè)COM對(duì)象可以有多個(gè)接口,而每個(gè)接口實(shí)質(zhì)上是一些函數(shù)的集合。
● 高內(nèi)聚
內(nèi)聚(Cohesion)是一個(gè)模塊內(nèi)部各成分之間相關(guān)聯(lián)程度的度量。內(nèi)聚程度從低到高大致劃分為低端、中段和高端,如圖3-15所示。模塊設(shè)計(jì)者沒(méi)有必要確定內(nèi)聚的精確級(jí)別,重要的是盡量爭(zhēng)取高內(nèi)聚,避免低內(nèi)聚。
順序性內(nèi)聚 功能性內(nèi)聚
時(shí)序性內(nèi)聚 過(guò)程性內(nèi)聚 通訊性內(nèi)聚
偶然性內(nèi)聚 邏輯性內(nèi)聚
低端… 中段… 高端…
各種內(nèi)聚類型的含義如下:
偶然性內(nèi)聚。如果一個(gè)模塊的各成分之間的關(guān)系彼此松散(幾乎無(wú)關(guān)),稱為偶然性內(nèi)聚。
邏輯性內(nèi)聚。幾個(gè)邏輯上相關(guān)的功能被放在同一模塊中,則稱為邏輯性內(nèi)聚。例如一個(gè)模塊讀取各種不同類型外設(shè)的輸入。
時(shí)序性內(nèi)聚。如果一個(gè)模塊內(nèi)的幾個(gè)功能必須在同一時(shí)間內(nèi)執(zhí)行(如系統(tǒng)初始化),但這些功能只是因?yàn)闀r(shí)間因素關(guān)聯(lián)在一起,則稱為時(shí)間性內(nèi)聚。
過(guò)程性內(nèi)聚。如果一個(gè)模塊內(nèi)部的處理成分是相關(guān)的,而且這些處理必須以特定的次序執(zhí)行,則稱為過(guò)程性內(nèi)聚。
通信內(nèi)聚。如果一個(gè)模塊的所有成分都操作同一數(shù)據(jù)集或生成同一數(shù)據(jù)集,則稱為通信內(nèi)聚。
順序內(nèi)聚。如果模塊內(nèi)的某個(gè)成分的輸出作為另一個(gè)成分的輸入,則稱為順序內(nèi)聚。
功能內(nèi)聚。模塊的所有成分對(duì)于完成單一的功能都是必須的,則稱為功能內(nèi)聚。
● 低耦合
耦合(Coupling)是模塊之間依賴程度的度量。內(nèi)聚和耦合是密切相關(guān)的,與其它模塊存在強(qiáng)耦合的模塊通常意味著弱內(nèi)聚,而強(qiáng)內(nèi)聚的模塊通常意味著與其它模塊之間存在弱耦合。
耦合的強(qiáng)度依賴于以下幾個(gè)因素:(1)一個(gè)模塊對(duì)另一個(gè)模塊的函數(shù)調(diào)用數(shù)量;(2)一個(gè)模塊向另一個(gè)模塊傳遞的數(shù)據(jù)量;(3)一個(gè)模塊施加到另一個(gè)模塊的控制的多少;(4)模塊之間接口的復(fù)雜程度。
耦合程度從低到高大致劃分為低端、中段和高端,如圖3-16所示。模塊設(shè)計(jì)應(yīng)當(dāng)爭(zhēng)取“高內(nèi)聚、低耦合”,而避免“低內(nèi)聚、高耦合”。
印記耦合 控制耦合
公共耦合 內(nèi)容耦合
非直接耦合 數(shù)據(jù)耦合
低端… 中段… 高端…
各種耦合類型的含義如下:
非直接耦合。模塊之間沒(méi)有直接的信息傳遞,稱為非直接耦合。
數(shù)據(jù)耦合。模塊之間通過(guò)接口傳遞參數(shù)(數(shù)據(jù)),稱為數(shù)據(jù)耦合。
標(biāo)記耦合。模塊間通過(guò)接口傳遞內(nèi)部數(shù)據(jù)結(jié)構(gòu)的一部分(而不是簡(jiǎn)單的參數(shù)),稱為印記(Stamp)耦合。此數(shù)據(jù)結(jié)構(gòu)的變化將使相關(guān)的模塊發(fā)生變化。
控制耦合。模塊傳遞信號(hào)(如開(kāi)關(guān)值、標(biāo)志量等)給另一個(gè)模塊,接收信號(hào)的模塊根據(jù)信號(hào)值調(diào)整動(dòng)作,稱為控制耦合。
公共耦合。兩個(gè)以上的模塊共同引用一個(gè)全局?jǐn)?shù)據(jù)項(xiàng),稱為公共耦合。
內(nèi)容耦合。當(dāng)一個(gè)模塊直接修改或操作另一個(gè)模塊的數(shù)據(jù),或者直接轉(zhuǎn)入另一個(gè)模塊時(shí),就發(fā)生了內(nèi)容耦合。
數(shù)據(jù)結(jié)構(gòu)與算法設(shè)計(jì)
設(shè)計(jì)高效率的程序是基于良好的數(shù)據(jù)結(jié)構(gòu)與算法,而不是基于編程小技巧。
一般說(shuō)來(lái),數(shù)據(jù)結(jié)構(gòu)與算法就是一類數(shù)據(jù)的表示及其相關(guān)的操作(這里算法不是指數(shù)值計(jì)算的算法)。從數(shù)據(jù)表示的觀點(diǎn)來(lái)看,存儲(chǔ)在數(shù)組中的一個(gè)有序整數(shù)表也是一種數(shù)據(jù)結(jié)構(gòu)。算法是指對(duì)數(shù)據(jù)結(jié)構(gòu)施加的一些操作,例如對(duì)一個(gè)線性表進(jìn)行檢索、插入、刪除等操作。一個(gè)算法如果能在所要求的資源限制(Resource Constraints)范圍內(nèi)將問(wèn)題解決好,則稱這個(gè)算法是有效率(Efficient)的。例如一個(gè)資源限制可能是“用于存儲(chǔ)數(shù)據(jù)的內(nèi)存有限”,或者“允許執(zhí)行每個(gè)子任務(wù)所需的時(shí)間有限”。一個(gè)算法如果比其它已知算法所需要的資源都少,這個(gè)算法也被稱為是有效率的。算法的代價(jià)(Cost)是指消耗的資源量。一般說(shuō)來(lái),代價(jià)是由一個(gè)關(guān)鍵資源例如時(shí)間或空間來(lái)評(píng)估的。
毋庸置疑,人們編寫(xiě)程序是為了解決問(wèn)題。只有通過(guò)預(yù)先分析問(wèn)題來(lái)確定必須達(dá)到的性能目標(biāo),才有希望挑選出正確的數(shù)據(jù)結(jié)構(gòu)。有相當(dāng)多的程序員忽視了這一分析過(guò)程,而直接選用某一個(gè)他們習(xí)慣使用的,但是與問(wèn)題不相稱的數(shù)據(jù)結(jié)構(gòu),結(jié)果設(shè)計(jì)出一個(gè)低效率的程序。如果使用簡(jiǎn)單的設(shè)計(jì)就能夠達(dá)到性能目標(biāo)時(shí),選用復(fù)雜的數(shù)據(jù)結(jié)構(gòu)也是沒(méi)有道理的。
人們對(duì)常用的數(shù)據(jù)結(jié)構(gòu)與算法的研究已經(jīng)相當(dāng)透徹,可以歸納出一些設(shè)計(jì)原則:
1) 一種數(shù)據(jù)結(jié)構(gòu)與算法都有其時(shí)間、空間的開(kāi)銷和收益。當(dāng)面臨一個(gè)新的設(shè)計(jì)問(wèn)題時(shí),設(shè)計(jì)者要徹底地掌握怎樣權(quán)衡時(shí)空開(kāi)銷和算法有效性的方法。這就需要懂得算法分析的原理,而且還需要了解所使用的物理介質(zhì)的特性(例如,數(shù)據(jù)存儲(chǔ)在磁盤(pán)上與存儲(chǔ)在內(nèi)存中,就有不同的考慮)。
2) 開(kāi)銷和收益有關(guān)的是時(shí)間——空間的權(quán)衡。通??梢杂酶蟮臅r(shí)間開(kāi)銷來(lái)?yè)Q取空間的收益,反之亦然。時(shí)間——空間的權(quán)衡普遍地存在于軟件開(kāi)發(fā)的各個(gè)階段中。
3) 設(shè)計(jì)人員應(yīng)該充分地了解一些常用的數(shù)據(jù)結(jié)構(gòu)與算法,避免不必要的重復(fù)設(shè)計(jì)工作。
4) 數(shù)據(jù)結(jié)構(gòu)與算法為應(yīng)用服務(wù)。我們必須先了解應(yīng)用的需求,再尋找或設(shè)計(jì)與實(shí)際應(yīng)用相匹配的數(shù)據(jù)結(jié)構(gòu)。
數(shù)據(jù)結(jié)構(gòu)與算法設(shè)計(jì)的一般流程如下:
(1)數(shù)據(jù)結(jié)構(gòu)與算法有全局和局部之分,當(dāng)然先設(shè)計(jì)全局的,后設(shè)計(jì)局部的(通常在模塊設(shè)計(jì)時(shí)進(jìn)行)。
(2)根據(jù)問(wèn)題的特征,先查找已經(jīng)存在的數(shù)據(jù)結(jié)構(gòu)與算法,挑選最合適的(并不一定是最先進(jìn)的)。如果不存在現(xiàn)成的,那么自己設(shè)計(jì)。
(3)設(shè)計(jì)并且編寫(xiě)代碼之后,要進(jìn)行測(cè)試。如果不滿足性能要求,那么要進(jìn)一步優(yōu)化數(shù)據(jù)結(jié)構(gòu)和算法。