簡述為什么要重視.NET代碼設(shè)計(jì)
.NET代碼設(shè)計(jì)的重點(diǎn)在于重視程度,也就是開發(fā)人員需要集中思想,提前做好準(zhǔn)備工作。如果不重視,很可能出現(xiàn)太多的public會讓使用這些class的二次開發(fā)的人員無所適從的局面。
為什么要重視.NET代碼設(shè)計(jì)?
在絕大多數(shù)項(xiàng)目中,尤其是在大型、資源缺少(這是軟件項(xiàng)目的典型現(xiàn)象)的項(xiàng)目中,正規(guī)的架構(gòu)可能只是解決系統(tǒng)級的事項(xiàng),而特意把大部分的設(shè)計(jì)工作留待代碼構(gòu)建階段去做。這可能會引發(fā)兩個問題:
<!--[if !supportLists]-->1) <!--[endif]-->代碼構(gòu)建階段的設(shè)計(jì)分散保存在開發(fā)人員的頭腦中,得不到有效的驗(yàn)證
<!--[if !supportLists]-->2) <!--[endif]-->由于開發(fā)人員各有所長,也各有所短,往往在進(jìn)行了部分或完成代碼構(gòu)建后,問題才能被明確。最終,不合理的設(shè)計(jì)導(dǎo)致大量的重構(gòu)工作,延誤項(xiàng)目工期。
設(shè)計(jì)工作千頭萬緒,然而軟件設(shè)計(jì)的首要使命是“管理復(fù)雜度”;重點(diǎn)和難點(diǎn)是“管理變化”。雖然“管理變化”是“管理復(fù)雜度”的內(nèi)容之一,但由于“管理變化”具有突出的重要性,因此單獨(dú)進(jìn)行介紹。在代碼構(gòu)建整個過程中,所有設(shè)計(jì)工作必須充分考慮這兩個方面,從而實(shí)現(xiàn)高質(zhì)量代碼。
<!--[if !supportLists]-->1. <!--[endif]-->管理復(fù)雜度
復(fù)雜度來源:
<!--[if !supportLists]-->1) <!--[endif]-->用復(fù)雜的方法解決簡單的問題
這個現(xiàn)象通常出現(xiàn)在過度設(shè)計(jì)上:首先是簡單的問題復(fù)雜化,然后對復(fù)雜化的問題使用復(fù)雜的方法。
如在10個有序數(shù)字中檢索某個數(shù)字。按照目前的CPU運(yùn)算速度,直接采用順序檢索簡單有效。如果盲目考慮CPU運(yùn)算的因素,采用二分法檢索,反而導(dǎo)致邏輯冗余。但是,如果對位數(shù)過萬的數(shù)組進(jìn)行檢索,則應(yīng)采用二分法或其它更有效的算法。
<!--[if !supportLists]-->2) <!--[endif]-->用簡單但錯誤的方法解決復(fù)雜的問題
由于設(shè)計(jì)是一個由淺入深,不斷嘗試,不斷失敗,最終得到正確結(jié)果的過程,因此,在代碼構(gòu)建之初,當(dāng)設(shè)計(jì)者未能正確考慮復(fù)雜問題的各個方面,將復(fù)雜問題簡單化后,將會導(dǎo)致“用簡單但錯誤的方法解決復(fù)雜的問題”。
對此,我說一下自己的一個切身體會,在SharePoint開發(fā)中,我們一個常見的問題是“內(nèi)容數(shù)據(jù)庫非關(guān)系型數(shù)據(jù)庫”,雖然Moss提供了Lookup類型的字段來建立這種關(guān)系,但是存在兩個問題,首先是不能跨站點(diǎn),更不能查詢多個列表的內(nèi)容,也不能綜合顯示多個字段的內(nèi)容。這些缺陷對于很多應(yīng)用來說,似乎是致命的。為此,我曾經(jīng)設(shè)計(jì)出同時支持跨網(wǎng)站、跨列表、多字段的自定義Field。但是設(shè)計(jì)中欠缺考慮,以致完成該Field的開發(fā)后,一個顯著的缺陷讓我頭疼不已:將關(guān)聯(lián)關(guān)系存儲與字段值中,雖然在顯示、編輯和存儲上簡化了編碼工作,但是卻未能解決關(guān)聯(lián)關(guān)系本質(zhì)上的問題,從而導(dǎo)致了一系列更為復(fù)雜的問題的出現(xiàn),如反向關(guān)聯(lián)查詢,關(guān)聯(lián)同步,以致于花費(fèi)了大量的精力來維護(hù)這種關(guān)系。
在該字段新版本的設(shè)計(jì)中,我將關(guān)聯(lián)關(guān)系單獨(dú)存儲在一個列表中,同時擴(kuò)展基內(nèi)容類型的New & Edit Form。嵌入維護(hù)不同列表間項(xiàng)與項(xiàng)關(guān)系的可視化展示與編輯部件(基于Silverlight實(shí)現(xiàn))。順便提一下,使用了多年的Flex,發(fā)現(xiàn)Silverlight除了在基礎(chǔ)組件庫上略遜色外,性能方面還是很不錯的,尤其是繼承自NET的垃圾回收機(jī)制。
但是無論是Flex和Silverlight,都要注意它在圖形繪制方面的局限性,當(dāng)需要繪制的組件和圖表過多時,盡量只繪制ViewPort中的部分,否則性能問題將導(dǎo)致整個程序的崩潰。
總結(jié)一下,如果使用簡單但錯誤的方法解決復(fù)雜問題,那么代價(jià)會在后面成幾何級數(shù)回饋給你。
套用一句話:代碼無小事!
<!--[if !supportLists]-->3) <!--[endif]-->用不恰當(dāng)?shù)膹?fù)雜方法解決復(fù)雜問題
在舊有經(jīng)驗(yàn)的指導(dǎo)下,某些復(fù)雜問題的表象會誤導(dǎo)設(shè)計(jì)者,將之當(dāng)作另外一個曾經(jīng)發(fā)生過的復(fù)雜問題,而問題本身的復(fù)雜程度也令人望而卻步,不愿做進(jìn)一步的分析,直接套用已有的解決方法雖然省事,卻有可能“用不恰當(dāng)?shù)膹?fù)雜方法解決復(fù)雜問題”。
管理復(fù)雜度的方法:
<!--[if !supportLists]-->1) <!--[endif]-->任何人在同一時間只處理必不可少的復(fù)雜度
<!--[if !supportLists]-->a) <!--[endif]-->分類匯總
從問題的領(lǐng)域著手,而不是從底層實(shí)現(xiàn)細(xì)節(jié)入手去編寫程序,在最抽象的層次上工作,也能減少人的腦力負(fù)擔(dān)。
問題的領(lǐng)域在不同抽象程度上,可以劃分為不同的級別:業(yè)務(wù),子系統(tǒng),功能模塊,類、子程序。通常,從較高的領(lǐng)域分解下來,會有效的降低問題的復(fù)雜程度。如在子系統(tǒng)級別確定好每個功能模塊接口,那么在進(jìn)入功能模塊領(lǐng)域后,你只需要關(guān)心少量的接口,而把更多的精力放在該功能的數(shù)據(jù)、邏輯和UI設(shè)計(jì)上。
C#等面向?qū)ο笳Z言可以輕易實(shí)現(xiàn)這種抽象,通過定義基類或抽象類(如C#中的abstract 關(guān)鍵字)。
<!--[if !supportLists]-->b) <!--[endif]-->一致的抽象
定義基類或抽象類時,必須保持同級別抽象的一致性,摒除不必要的細(xì)節(jié)。
如ASP.NET編程中的Page和Control就屬于同一級別的抽象。 在Page類的實(shí)現(xiàn)中,它無需知道具體是什么類型的Control,是DataGrid還是TextBox,它根本不關(guān)心,它只關(guān)心Control類中的Render()可以提供什么樣的Html。而這個Control是紅的還是綠的,是方的還是圓的,根本不需要關(guān)心。如果編寫Page類時調(diào)用了Control的一個子類,那抽象就不一致了,Page將自動降級,Page對于Control基類毫無意義。當(dāng)然,這樣的錯誤誰也不會去犯,僅僅用來說明這個道理而已。
在SharePoint中,通常我們也會實(shí)現(xiàn)一些基礎(chǔ)類以提高團(tuán)隊(duì)的開發(fā)效率,如BaseAjaxWebPart、BaseAjaxField等等。這些Base類中一定不要使用某些實(shí)現(xiàn)了特定細(xì)節(jié)的類或組件。
<!--[if !supportLists]-->2) <!--[endif]-->不要讓偶然性的復(fù)雜度無謂地快速增長
偶然性的復(fù)雜度,即潛在的變化,包括:已知的未知、未知的未知。
對于未知的未知這種情況,我們可以不過多考慮,只需要根據(jù)經(jīng)驗(yàn)在任務(wù)工期上預(yù)留一定資源:時間、人力等。
對于已知的不確定的變化,在下面《管理變化》中簡要介紹。
<!--[if !supportLists]-->2. <!--[endif]-->管理變化
沒有變化的程序是不可能存在的。但不能讓變化像病毒一樣蔓延到整個程序。
管理變化的手段比較多,如24種設(shè)計(jì)模式,大部分都是解決這個問題的。但萬變不離其宗,主要還是以下兩個方面:
<!--[if !supportLists]-->1) <!--[endif]-->封裝
通過有效的繼承和一致的抽象,可以確保發(fā)生變化時,最小的代碼改動量。
<!--[if !supportLists]-->2) <!--[endif]-->模塊化
通過對系統(tǒng)模塊化及劃分界面,確定接口,可以有效地將變化控制在模塊內(nèi)部。
使用封裝和模塊化來管理變化時,必須注意隱藏信息:該使用private之處,絕不要使用protected。該使用protected之處,絕不要使用public。Internal也不要多用,它的作用域是程序集內(nèi)部,在編寫代碼時,往往跟public一樣混淆視聽,降低了代碼的可讀性。
太多的public會讓使用這些class的二次開發(fā)的人員無所適從。充斥著非必要public成員的class,不符合管理復(fù)雜度的原則。有可能是設(shè)計(jì)原因,也有可能是未按照設(shè)計(jì)嚴(yán)格編碼。
.NET代碼設(shè)計(jì)的要點(diǎn)就介紹到這里。
原文標(biāo)題:談?wù)劥a設(shè)計(jì)
鏈接:http://www.cnblogs.com/ghner/archive/2009/09/05/1560998.html
【編輯推薦】