版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、面向?qū)ο笤O(shè)計(jì)思想(C#)2009-10-05 23:33有了思想才能飛翔,缺乏靈活就象少了輪子的汽車,難以飛奔。為了更好的理解設(shè)計(jì)思想,結(jié)合一個盡可能簡潔的實(shí)例來說明OOD、設(shè)計(jì)模式及重構(gòu)。通過下面的代碼,詳細(xì)地闡述面向?qū)ο笤O(shè)計(jì)思想。一、傳統(tǒng)過程化設(shè)計(jì)思想假定我們要設(shè)計(jì)一個媒體播放器(只從軟件設(shè)計(jì)的角度,不涉及硬件)。該媒體播放器目前只支持音頻文件mp3和wav。按照結(jié)構(gòu)化設(shè)計(jì)思想,設(shè)計(jì)出來的播放器的代碼如下:public class MediaPlayerprivate void PlayMp3()MessageBox.Show("Play the mp3 file.")
2、;private void PlayWav()MessageBox.Show("Play the wav file.");public void Play(string audioType)switch (audioType.ToLower()case ("mp3"):PlayMp3();break;case ("wav"):PlayWav();break;從傳統(tǒng)的過程化設(shè)計(jì)思想來看,這是一段既實(shí)用又簡潔的代碼。如果,客戶又提出新的要求:要播放器不僅僅播放mp3和wav文件,還要播放其他音頻文件如wma、mp4等,為此我們要不斷地增加
3、相應(yīng)地播放方法和修改條件語句,直止條件語句足夠長。如果,客戶感到這個媒體播放器功能太少了,只能聞其聲,不能見其人,太單一。如果在聽著優(yōu)美音樂的同時又能看到歌唱者瀟灑、英俊的舞姿那就更好了。從代碼設(shè)計(jì)的角度看,他們希望媒體播放器支持視頻文件了。也許你會想,不會再增加視頻這方面的代碼,可以,在增加視頻媒體的播放方法,在修改條件判斷語句,如果還有其他,還可以同樣地增加、修改。到此你也許會提出,要是不修改或很少修改原來的代碼就能增添其他功能該多好??!這樣看,原來的軟件設(shè)計(jì)結(jié)構(gòu)似乎有點(diǎn)問題。事實(shí)上,隨著功能的不斷增加,你越來越發(fā)現(xiàn)這個設(shè)計(jì)非常的糟糕,因?yàn)樗緵]有為未來的需求變更提供最起碼的擴(kuò)展。為了應(yīng)
4、接不暇的變更需求,你不得不不厭其煩地修改原來的代碼,使其適應(yīng)需求變化,甚至在修改代碼時,由于過多的代碼依賴關(guān)系弄得人焦頭爛額,直止一塌糊涂。二、面向?qū)ο笤O(shè)計(jì)思想還是以設(shè)計(jì)一個媒體播放器為例,設(shè)計(jì)要求相同。不訪我們換個設(shè)計(jì)思路利用面向?qū)ο笤O(shè)計(jì)思想(OOD)來做做看如何!根據(jù)OOD的思想,我們應(yīng)該把mp3和wav分別看作是兩個獨(dú)立的對象。代碼設(shè)計(jì)如下:public class MP3public void Play()MessageBox.Show("Play the mp3 file.");public class WAVpublic void Play()MessageBo
5、x.Show("Play the wav file.");Public class MediaPlayerswitch (audioType.ToLower()case ("mp3"):MP3 m = new MP3();m.Play();break;case ("wav"):WAV w = new WAV();w.Play();break;現(xiàn)在我們重構(gòu)代碼,建立統(tǒng)一的Play()方法,(在后面的設(shè)計(jì)中,你會發(fā)現(xiàn)這樣改名是多么的重要!)更改媒體播放類MediaPlayer的代碼。如果這樣的設(shè)計(jì)代碼,實(shí)質(zhì)上沒有多大的變化,只是對原來過程
6、化設(shè)計(jì)思想的一種替代,并沒有擊中要害,亦然沒有靈活性、可擴(kuò)展性。2.1單向分派技術(shù)的應(yīng)用(在這里用類的多態(tài)來實(shí)現(xiàn)的)我們不訪這樣設(shè)想:既然mp3和wav都屬于音頻文件,都具有音頻文件的共性,應(yīng)該建立一個共同的AudioMedia父類。public class AudioMediapublic void Play()MessageBox.Show("Play the AudioMedia file.");現(xiàn)在引入繼承思想,OOD就有點(diǎn)雛形了(不是說有了繼承就有了OOD思想,這里只是從繼承的角度談一談OOD思想,當(dāng)然從其他角度如合成、聚合等角度也能很好地體現(xiàn)OOD思想)。其實(shí)在
7、現(xiàn)實(shí)生活中,我們的播放器播放的只能是某種具體類型的音頻文件如mp3,因此這個AudioMedia類只能是音頻媒體的一個抽象化概念,并沒有實(shí)際的使用情況。對應(yīng)在OOD設(shè)計(jì)中,既這個類永遠(yuǎn)不會被實(shí)例化。為此我們應(yīng)將其改為抽象類,如下:public abstract class AudioMediapublic abstract void Play();public class MP3:AudioMediapublic override void Play()MessageBox.Show("Play the mp3 file.");public class WAV:AudioM
8、ediapublic override void Play()MessageBox.Show("Play the wav file.");public class MediaPlayer/根據(jù)需要完成任務(wù)的單向分派public void Play(AudioMedia media)media.Play();到此,我們通過單向分派技術(shù)使OOD思想得到進(jìn)一步的體現(xiàn)?,F(xiàn)在的設(shè)計(jì),即滿足了類之間的層次關(guān)系,又保證了類的最小化原則,同時又體現(xiàn)了面向?qū)ο笤O(shè)計(jì)原則(開閉原則、里氏代換原則)更利于擴(kuò)展。(止此,你會發(fā)現(xiàn)play方法名的更改是多么必要)。如果現(xiàn)在又增加了對WMA、MP4等音頻
9、文件的播放,只需要設(shè)計(jì)WMA類,MP4類,并繼承AudioMedia,在相應(yīng)的子類中重寫Play方法就可以了,MediaPlayer類對象的Play方法根本不用任何改變。如果讓媒體播放器能夠支持視頻文件,必須另外設(shè)計(jì)視頻媒體的類。因視頻文件和音頻文件有很多不同的地方,不可能讓視頻繼承音頻。假設(shè)我們播放器支持RM和MPEG格式的視頻。視頻類代碼如下:public abstract class VideoMediapublic abstract void Play();public class RM:VideoMediapublic override void Play()MessageBox.S
10、how("Play the rm file.");public class MPEG:VideoMediapublic override void Play()MessageBox.Show("Play the mpeg file.");這樣設(shè)計(jì)還是有點(diǎn)糟糕,這樣就無法實(shí)用原有的MediaPlayer類了。因?yàn)槟阋シ诺囊曨lRM文件并不是音頻媒體AudioMedia的子類。不過,我們可以這樣想,無論音頻媒體還是視頻媒體都是媒體,有很多相似的功能,如播放、暫停、停止等,為此我們把“媒體”這個概念抽象出來做為一個接口。(雖然也可以用抽象類,但在C#里只支持類
11、的單繼承,不過c#支持接口的多繼承)。根據(jù)接口的定義,你完全可以將相同功能的一系列對象實(shí)現(xiàn)同一個接口。讓音頻媒體類及視頻媒體類都繼承媒體這個接口。代碼如下:public interface IMediavoid Play();public abstract class AudioMedia:IMediapublic abstract void Play();public abstract class VideoMedia:IMediapublic abstract void Play();這樣再更改MediaPlayer類的代碼:public class MediaPlayerpublic v
12、oid Play(IMedia media)media.Play();現(xiàn)在看來,程序是不是有很大的靈活性和可擴(kuò)展性了??偨Y(jié)一下,從MediaPlayer類的演變,我們可以得出這樣一個結(jié)論:在調(diào)用類對象的屬性和方法時,盡量避免將具體類對象作為傳遞參數(shù),而應(yīng)傳遞其抽象對象,更好地是傳遞接口,將實(shí)際的調(diào)用和具體對象完全剝離開,這樣可以很好地體現(xiàn)了軟件工程的靈活性、擴(kuò)展性?,F(xiàn)在看起來似乎很完美了,但我們忽略了MediaPlayer的調(diào)用者這個事實(shí)。仍然需要條件語句來實(shí)現(xiàn)。例如,在客戶端程序代碼中,用戶通過選擇cbbMediaType組合框的選項(xiàng),決定播放音頻媒體還是視頻媒體,然后單擊Play按鈕執(zhí)行。
13、Public void BtnPlay_Click(object sender,EventArgs e)IMedia media = null;case ("mp3"):media = new MP3();break;/其它類型略;case ("rm"):media = new RM();break;/其它類型略;MediaPlayer player = new MediaPlayer();player.Play(media);2.2設(shè)計(jì)模式、條件外置及反射技術(shù)的應(yīng)用隨著需求的增加,程序?qū)絹碓綇?fù)雜。此時就應(yīng)調(diào)整設(shè)計(jì)思想,充分考慮到代碼的重構(gòu)和設(shè)計(jì)模式
14、的應(yīng)用。最后當(dāng)設(shè)計(jì)漸趨完美后,你會發(fā)現(xiàn),即使需求不斷增加,你也可以神清氣爽,不用為代碼設(shè)計(jì)而煩惱了。為了實(shí)現(xiàn)軟件工程的三個主要目標(biāo):重用性、靈活性和擴(kuò)展性。我們不訪用設(shè)計(jì)模式、條件外置及反射來實(shí)現(xiàn)。使用工廠模式,能夠很好地根據(jù)需要,調(diào)用不同的對象(即動態(tài)調(diào)用),保證了代碼的靈活性。雖然這里有兩種不同類型的媒體AudioMedia和VideoMedia(以后可能更多),但它們同時又都實(shí)現(xiàn)IMedia接口,所以我們可以將其視為一種產(chǎn)品。媒體工廠接口如下:public interface IMediaFactoryIMedia CreateMedia();然后為具體的媒體文件對象搭建工廠,并統(tǒng)一實(shí)現(xiàn)
15、媒體工廠接口:public class MP3Factory:IMediaFactorypublic IMedia CreateMedia()return new MP3();/其它工廠略;public class RMFactory:IMediaFactorypublic IMedia CreateMedia()return new RM();/其它工廠略;寫到這里,也許有人會問,為什么不直接給AudioMedia和VideoMedia類搭建工廠呢?很簡單,因?yàn)樵贏udioMedia和VideoMedia中,分別還有不同的類型派生,如果為它們搭建工廠,則在CreateMedia()方法中,仍
16、然要使用條件判斷語句,代碼缺乏靈活性,不利擴(kuò)展。還有一個問題,就是真的有必要實(shí)現(xiàn)AudioMedia和VideoMedia兩個抽象類嗎?讓其子類直接實(shí)現(xiàn)接口不是更簡單?對于本文提到的需求,是能實(shí)現(xiàn)的。但不排除AudioMedia和VideoMedia它們還會存在其他區(qū)別,如音頻文件還需給聲卡提供接口,而視頻文件還需給顯卡提供接口。如果讓MP3、WAV、RM、MPEG直接實(shí)現(xiàn)IMedia接口,而不通過AudioMedia和VideoMedia,在滿足其它需求的設(shè)計(jì)上也是不合理的。現(xiàn)在客戶端程序代碼發(fā)生了稍許的改變:Public void BtnPlay_Click(object sender,E
17、ventArgs e)IMediaFactory factory = null;/音頻媒體case ("mp3"):factory = new MP3Factory();break;/視頻媒體case ("rm"):factory = new RMFactory();break;/其他類型略;MediaPlayer player = new MediaPlayer();player.Play(factory.CreateMedia();到這里,我們再回過頭來看MediaPlayer類。這個類中通過單向分派,根據(jù)傳遞參數(shù)的不同,分別實(shí)現(xiàn)了不同對象的Play
18、方法。在不用工廠模式時,這個類對象會運(yùn)行得很好。作為一個類庫或組件設(shè)計(jì)者來看,他提供了一個不錯的接口,供客戶端程序調(diào)用。利用工廠模式后,現(xiàn)在看來MediaPlayer類已經(jīng)多余。所以,我們要記住的是,重構(gòu)并不僅僅是往原來的代碼添加新的內(nèi)容。當(dāng)我們發(fā)現(xiàn)一些不必要的設(shè)計(jì)時,還需要果斷地刪掉這些冗余代碼。修改后的代碼如下:Public void BtnPlay_Click(object sender,EventArgs e)IMediaFactory factory = null;case ("mp3"):factory = new MP3Factory();break;/其他類
19、型略;case ("rm"):factory = new RMFactory();break;/其他類型略;IMedia media = factory.CreateMedia();media.Play();如果你在最開始沒有體會到IMedia接口的好處,在這里你應(yīng)該已經(jīng)明白了。我們在工廠模式中用到了該接口;而在客戶端程序中,仍然要使用該接口。使用接口有什么好處?那就是你的主程序可以在沒有具體業(yè)務(wù)類的時候,同樣可以編譯通過。因此,即使你增加了新的業(yè)務(wù),你的客戶端程序是不用改動的。不過,這樣寫客戶端代碼還是不夠理想的,依然不夠靈活,在判斷具體創(chuàng)建哪個工廠的時候,仍需條件判斷。
20、現(xiàn)在看來,如果執(zhí)行者沒有完全和具體類分開,一旦更改了具體類的業(yè)務(wù),例如增加了新的工廠類,仍然需要更改客戶端程序代碼。我們可以通過反射技術(shù)、條件外置很好地做到客戶端的靈活性。條件外置來實(shí)現(xiàn),即通過應(yīng)用程序的配置文件來實(shí)現(xiàn)。我們可以把每種媒體文件類的類型信息放在配置文件中,然后根據(jù)配置文件來選擇創(chuàng)建具體的對象。并且,這種創(chuàng)建對象的方法將使用反射技術(shù)來完成。首先,創(chuàng)建配置文件:<appSettings><add key="mp3" value="MediaLibrary.MP3Factory" /><add key="w
21、av" value=" MediaLibrary.WAVFactory" /><add key="rm" value=" MediaLibrary.RMFactory" /><add key="mpeg" value=" MediaLibrary.MPEGFactory" /></appSettings>然后,在客戶端程序代碼中,自定義一個初始化方法如:InitMediaType(),讀取配置文件的所有key值,填充cbbMediaType組合框控件中:private void InitMediaType()cb
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 化妝品店客戶服務(wù)與管理手冊(標(biāo)準(zhǔn)版)
- 現(xiàn)代文閱讀題目及答案
- 注冊安全工程師考試化工安全實(shí)務(wù)歷年真題題庫及答案
- 物流工程專業(yè)職稱考試試題及答案
- 2025年度基層崗位練兵和技能競賽(護(hù)理組)試題及答案
- 培訓(xùn)班學(xué)生考勤制度培訓(xùn)班學(xué)員考勤管理制度
- 醫(yī)院護(hù)理招聘筆試大題庫及答案解析
- 2025年【高壓電工】考試題及答案
- 2025三基護(hù)理筆試題目及答案
- 支隊(duì)政府專職消防員招聘179人筆試模擬試題含答案詳解
- 2026年藥廠安全生產(chǎn)知識培訓(xùn)試題(達(dá)標(biāo)題)
- 2026年陜西省森林資源管理局局屬企業(yè)公開招聘工作人員備考題庫及參考答案詳解1套
- 承包團(tuán)建燒烤合同范本
- 口腔種植牙科普
- 2025秋人教版七年級全一冊信息科技期末測試卷(三套)
- 搶工補(bǔ)償協(xié)議書
- SL631水利水電工程單元工程施工質(zhì)量驗(yàn)收標(biāo)準(zhǔn)第1部分:土石方工程
- 英語A級常用詞匯
- (二調(diào))武漢市2025屆高中畢業(yè)生二月調(diào)研考試 英語試卷(含標(biāo)準(zhǔn)答案)+聽力音頻
- 汽車修理廠輪胎采購 投標(biāo)方案(技術(shù)標(biāo) )
- 2023年7月浙江省普通高中學(xué)業(yè)水平考試(學(xué)考)化學(xué)試題
評論
0/150
提交評論