深入淺出設(shè)計(jì)模式第一_第1頁
深入淺出設(shè)計(jì)模式第一_第2頁
深入淺出設(shè)計(jì)模式第一_第3頁
深入淺出設(shè)計(jì)模式第一_第4頁
深入淺出設(shè)計(jì)模式第一_第5頁
已閱讀5頁,還剩29頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、模擬鴨子先從簡(jiǎn)單的模擬鴨子應(yīng)用做起Joe上班的公司做了一套相當(dāng)?shù)哪M鴨子游戲SimUDuck 游戲中出現(xiàn)各種鴨子,一邊游泳戲水,一邊呱呱叫。此系統(tǒng)的內(nèi)部設(shè)計(jì)使用了標(biāo)準(zhǔn)的OO Superclass),并讓各種鴨子繼技術(shù),設(shè)計(jì)了一個(gè)鴨子超類( 此超類。所有的鴨子都會(huì)呱呱叫(Quack)也會(huì)游泳(Swim),所以由超類負(fù)責(zé)處理這部分的實(shí)現(xiàn)代碼。去年,公司的競(jìng)爭(zhēng)加劇。在一個(gè)星期長(zhǎng)的假期兼頭腦風(fēng)暴會(huì)議之后,公司主管認(rèn)為該是創(chuàng)新的時(shí)候了,他們需要在下周股東會(huì)議上展示一些真正讓人印象深刻的東西來振奮人心。2第一章RedheadDuckdisplay() / 外觀是紅頭 MallardDuckdisplay(

2、) / 外觀是綠頭 Duckquack() swim() display()/ 鴨子的其他介紹設(shè)計(jì)模式現(xiàn)在我們得讓鴨子能飛主管認(rèn)為,此模擬程序需要會(huì)飛的競(jìng)爭(zhēng)者拋在后頭。當(dāng)然,在這個(gè)時(shí)候,Joe的經(jīng)理拍胸脯告訴主管們, Joe只需要一個(gè)星期就可以搞定,畢竟,Joe是一個(gè)OO 我只需要在Duck類中加上程序員.這有什么?fly() ,然后所有鴨子都會(huì)繼承fly()。這是我大顯身手,展示OO才華的時(shí)候了。Joe 我們想要的目前位置 3RedheadDuckdisplay() / 外觀是紅頭 MallardDuckdisplay() / 外觀是綠頭 Duckquack() swim() display

3、()fly()/ 鴨子的其他. 事情出錯(cuò)了但是,可怕的問題發(fā)生了 .Joe,我正在股東會(huì)議上, 剛剛看了一下展示,有一只橡皮鴨子在屏幕上飛來飛去,這是你開的玩笑嗎?你可能要開始去逛逛M(編注:站)了.最大的求職網(wǎng)怎么回事? Joe忽略了一件事:并非Duck 所有的子類都會(huì)飛。當(dāng)Joe在Duck超類中加上新的行為,這會(huì)使得某些子類也具有這個(gè)不恰當(dāng)?shù)男袨椤,F(xiàn)在好吧!我承認(rèn)設(shè)計(jì)中有一點(diǎn)小疏失。但是,他們?cè)趺床桓纱喟堰@當(dāng)特色,其實(shí)還挺有趣的呀.可好了!SimUDuck 飛的非動(dòng)物。有一個(gè)會(huì)對(duì)代碼所做的局部修改,影響層面可能不只局部(會(huì)飛的橡皮鴨)! 他 體 會(huì) 到 了 件 事 : 當(dāng)涉及維護(hù)時(shí),為了復(fù)

4、用(reuse) 目的而使用繼承,結(jié)局并不完美。4第一章RubberDuckquack() / 覆蓋成吱吱叫display() / 外觀是橡皮鴨RedheadDuckdisplay() / 外觀是紅頭MallardDuckdisplay() / 外觀是綠頭Duckquack() swim() display() fly()/ 鴨子的其他介紹設(shè)計(jì)模式Joe想到繼承,如果以后我加入誘餌鴨(DecoyDuck),又會(huì)如何?誘餌鴨是假鴨, 我可以把橡皮鴨類 中的fly() 覆蓋掉,就好像覆蓋quack()的作法一樣.飛也叫. 削尖你的鉛筆利用繼承提供鴨子行為,會(huì)導(dǎo)致下列哪些缺點(diǎn)?(多選) D. 難以得

5、知所有鴨子的全部行為。E. 鴨子不能同時(shí)又飛又叫。F. 改變會(huì)牽一發(fā)動(dòng)全身,造成其他鴨子不想要的改變。目前位置 A. 代碼在多個(gè)子類中重復(fù)。B. 運(yùn)行時(shí)的行為不容易改變。C. 我們不能讓鴨子跳舞。5DecoyDuckquack() / 覆蓋,變成什么事都不做display() / 誘餌鴨 fly() / 覆蓋,變成什么事都不做RubberDuckquack() / 吱吱叫 display() / 橡皮鴨 fly() / 覆蓋,變成什么事都不做繼承並非利用接口如何? Joe認(rèn)識(shí)到繼承可能不是一個(gè)解決,因?yàn)樗麆倓偰玫絹砉艿膫渫洠M院竺苛鶄€(gè)我可以把fly()取出來,放進(jìn)一個(gè)Flyable接口中

6、。這么一來,只有會(huì)飛的鴨子才實(shí)現(xiàn)此接口。同樣的方式,也可以用來設(shè)計(jì)一個(gè)Quackable接口,因?yàn)椴皇撬械镍喿佣紩?huì)叫。月更新(至于更新的,他們還沒想到)。Joe知道規(guī)格會(huì)常常改變,每當(dāng)有新的出現(xiàn),他就要被迫檢視并可能需要覆蓋fly() quark(). 這簡(jiǎn)直是無窮盡的惡夢(mèng)。類和所以,他需要一個(gè)更清晰的,讓某些(而不是全部)鴨子類型可飛或可叫。你覺得這個(gè)設(shè)計(jì)如何? 6第一章DecoyDuckdisplay()RubberDuckdisplay() quack()RedheadDuckdisplay() fly() quack()MallardDuckdisplay() fly() quack

7、()Flyablefly()Quackablequack()Duckswim()display()/ 鴨子的其他. 介紹設(shè)計(jì)模式這真是一個(gè)超笨的主意,你沒發(fā)現(xiàn)這么一來重復(fù)的代碼會(huì)變多嗎?如果你認(rèn)為覆蓋幾個(gè)就算是差勁,那么對(duì)于在48個(gè)Duck的子類都要稍微修改一下飛行的行為,你又怎么說?!如果你是Joe,你要怎么辦? 我們知道,并非所有的子類都具有飛行和呱呱叫的行為,所以繼承并不是適當(dāng)?shù)慕鉀Q方式。雖然Flyable 與Quackable 可以解決一部分的問題( 再有會(huì)飛的橡皮鴨),但是卻造成代碼無法復(fù)用,這只能算是從一個(gè)惡夢(mèng)跳進(jìn)另一個(gè)惡夢(mèng)。甚至,在會(huì)飛的鴨子中,飛行的動(dòng)作可能還有多種變化. 此時(shí)

8、,你可能正期盼著設(shè)計(jì)模式能騎著白馬來你苦難的一天。但是, 如果直接告訴你道:采用良,這有什么樂趣?我們會(huì)用老設(shè)計(jì)原則。找出一個(gè)解決之OO 如果能有一種建立的方法,好讓我們需要改變時(shí), 可以在對(duì)既有的代碼影響最小的情況下, 輕易地達(dá)成,花較少時(shí)間重新整理程序, 而多讓程序去做更酷的事。該有多好.目前位置 7不變的是變化開發(fā)的一個(gè)不變真理好吧!在開發(fā)上,有什么是你可以深信不疑的? 不管你在何處工作,建造些什么,用何種程序語言,在開發(fā)上,有沒有一個(gè)不變的真理? (用鏡子來看)不管當(dāng)初設(shè)計(jì)得多好,一陣子之后,總是需要成長(zhǎng)與改變, 否則就會(huì)。削尖你的鉛筆驅(qū)使改變的因素很多。找出你的應(yīng)用中需要改變代碼的地

9、方,一一列出來。(我們先起個(gè)頭,好讓你有個(gè)方向。) 我們的顧客或用戶需要?jiǎng)e的東西,或者想要新功能。公司決定采用別的數(shù)據(jù)庫這造成數(shù)據(jù)格式不兼容。唉!,也從另一家廠商買了不同的數(shù)據(jù),8第一章介紹設(shè)計(jì)模式把問題歸零現(xiàn)在我們知道使用繼承有一些缺失,因?yàn)楦淖凐喿拥男袨闀?huì)影響所有種類的鴨子,而這并不恰當(dāng)。Flyable與Quackable 接口一開始似乎還挺不錯(cuò),解決了問題(只有會(huì)飛的鴨子才繼承Flyable),但是Java 的接口不具有實(shí)現(xiàn)代碼,所以繼承接口無法達(dá)到代碼的復(fù)用。這意味著:無論何時(shí)你需要修改某個(gè)行為,你被迫得往下追蹤并修改每一個(gè)有定義此行為的把會(huì)變化的部分取出并封裝起來,好類,一不,可能造

10、成新的錯(cuò)誤。幸運(yùn)地,有一個(gè)設(shè)計(jì)原則,正適用于此狀況。讓其他部分影響。受到結(jié)果如何?代碼變化之后,出其不意的部分變得很少,系統(tǒng)變得更有彈性。換句話說,如果每次新的需求一來,都會(huì)變化到某方面的代碼,那么你就可以確定,這部分的代碼需要被抽出來,和其他聞風(fēng)不動(dòng)的代碼有所區(qū)隔。下面是這個(gè)原則的另一個(gè)思考方式:把會(huì)變化的部分取出并封裝起來,以便以后可以輕易地?cái)U(kuò)充此部分,而不影響不需要變化的其他部分。這樣的概念很簡(jiǎn)單,幾乎是每個(gè)設(shè)計(jì)模式背后的精神所在。所有的模式都提供了一套其他部分。讓系統(tǒng)中的某部分改變影響好,該是把鴨子的行為從Duck 類中取出的時(shí)候了! 目前位置 9設(shè)計(jì)原則找出應(yīng)用中可能需要變化之處,

11、把它們出來,不要和那些不需要變化的代碼混在一起。抽出變動(dòng)的部分變化和變化的部分如何開始?就我們目前所知,除了fly() 和quack() 的問題之外,Duck類還算一切正常,似乎沒有特別需要經(jīng)常變化或修改的地方。所以,除了某些小改變之外,我們不打算對(duì)Duck類做太多處理?,F(xiàn)在,為了要變化和變化的部分,我們準(zhǔn)備建立兩組類(完全遠(yuǎn)離Duck類), 一個(gè)是fly相關(guān)的,一個(gè)是quack相關(guān)的,每一組類將實(shí)現(xiàn)各自的動(dòng)作。比方說,我們可能有一個(gè)類實(shí)現(xiàn)呱呱叫,另一個(gè)類實(shí)現(xiàn)吱吱叫,另一個(gè)類實(shí)現(xiàn)安靜。我們知道Duck類內(nèi)的fly() 和quack() 會(huì)隨著鴨子的不同而改變。為了要把這兩個(gè)行為從Duck類中取

12、出,建立一組新類代表每個(gè)行為。,把它們自Duck類中10第一章取出易于變化的部分行鴨子行為介紹設(shè)計(jì)模式設(shè)計(jì)鴨子的行為如何設(shè)計(jì)類實(shí)現(xiàn)飛行和呱呱叫的行為? 我們希望一切能有彈性,畢竟,正是因?yàn)橐婚_始的鴨子行為沒有彈性,才讓我們走上現(xiàn)在這條路。我們還想能夠指定行為到鴨子的實(shí)例,比方說,想要產(chǎn)生綠頭鴨實(shí)例,并指定特定類型的飛行行為給它。干脆順便讓鴨子的行為可以動(dòng)態(tài)地改變好了。換句話說,我們應(yīng)該在鴨子類中包含設(shè)定行為的就可以在運(yùn)行時(shí)動(dòng)態(tài)地改變綠頭鴨的飛行行為。,從現(xiàn)在開始,鴨子的行為將被放在的類中,有了這些目標(biāo)要達(dá)成,接著看看第二個(gè)設(shè)計(jì)原則: 此類專門提供某行為的實(shí)現(xiàn)。如此,鴨子類就不再需要知道行為的實(shí)

13、現(xiàn)細(xì)節(jié)。我們利用接口代表每個(gè)行為,比方說, FlyBehavior與QuackBehavior,而行為的每個(gè)實(shí)現(xiàn)都必須實(shí)現(xiàn)這些接口之一。所以這次鴨子類負(fù)責(zé)實(shí)現(xiàn)Flying與Quacking接口,反而是由其他類專門實(shí)現(xiàn)FlyBehavior 與QuackBehavior,這就稱為行為類。由行為類實(shí)現(xiàn)行為接口,而不是由Duck類實(shí)現(xiàn)行為接口。這樣的作法迥異于以往,以前的作法是:行為是繼Duck 超類的具體實(shí)現(xiàn)而來,或是繼承某個(gè)接口并由子類自行實(shí)現(xiàn)而來。這兩種作法都是依賴于實(shí)現(xiàn),我們被實(shí)現(xiàn)綁得死死的,沒辦法更改行為(除非寫代碼)。在我們的新設(shè)計(jì)中,鴨子的子類將使用接口(FlyBehavior與Qua

14、ckBehavior)所表示的行為,所以實(shí)際的實(shí)現(xiàn)被綁死在鴨子的子類中。(換句話說,特定的實(shí)現(xiàn)代碼,是位于實(shí)現(xiàn)FlyBehavior 與QuakcBehavior 的特定類中)。目前位置 11FlyNoWayfly() / 什么都不做,飛! FlyWithWingsfly() / 實(shí)現(xiàn)鴨子的飛行動(dòng)作<<interface>>FlyBehaviorfly()設(shè)計(jì)原則接口編程,而不是實(shí)現(xiàn)編程。接口編程我不懂你為什么要把 FlyBehavior設(shè)計(jì)成接口,為何不使用抽象超類,這樣不就可以使用多態(tài)嗎?接口編程真正的意思是超類型(supertype) 編程。這里所謂的接口有多個(gè)含

15、意,接口是一個(gè)概念, 也是一種Java的interface構(gòu)造。你可以在不涉及Java interface的情況下,接口編程,關(guān)鍵就在多態(tài)。利用多態(tài),程序可以超類型編程,執(zhí)行時(shí)會(huì)根據(jù)實(shí)際狀況執(zhí)行到真正的行為, 被綁死在超類型的行為上。針對(duì)超類型編程這句話,可以更明確地說成變量的類型,應(yīng)該是超類型,通常是一個(gè)抽象類或者是一個(gè)接口,如此,只要是具體實(shí)現(xiàn)此超類型的類所產(chǎn)生的對(duì)象,都可以指定給這個(gè)變量;這也意味著, 時(shí)的真正對(duì)象類型!類時(shí),不用理會(huì)以后執(zhí)行這可能不是你第一次聽到,但是請(qǐng)務(wù)必注意我們想的是同一件事。看看下面這個(gè)簡(jiǎn)單的多態(tài)范例:假設(shè)有一個(gè)抽象類Animal,有兩個(gè)具體的實(shí)現(xiàn)(Dog與Cat

16、)繼實(shí)現(xiàn)編程,作法如下: Animal。Dog d = new Dog(); d.bark();但是接口/超類型編程,作如同下面: Animal animal = new Dog(); animal.makeSound();更棒的是,子類型實(shí)例化的動(dòng)作不再需要在代碼中硬編碼, 例如new Dog(),而是在運(yùn)行時(shí)才指定具體實(shí)現(xiàn)的對(duì)象。a = getAnimal(); a.makeSound();12第一章CatmakeSound() meow();meow() / 喵喵叫 DogmakeSound() bark();bark() / 汪汪叫 AnimalmakeSound()介紹設(shè)計(jì)模式實(shí)現(xiàn)鴨

17、子的行為在此,我們有兩個(gè)接口,F(xiàn)lyBehavior和QuackBehavior,還有它們對(duì)應(yīng)的類,負(fù)責(zé)實(shí)現(xiàn)具體的行為: 目前位置 13這樣的設(shè)計(jì),可以讓飛行和呱呱叫的動(dòng)作被其他的對(duì)象復(fù)用,因?yàn)檫@些行為已經(jīng)與鴨子類無關(guān)了。而我們可以 些行為, 影響到既有的行為類,也 影響有使用到飛行行為的鴨子類。MuteQuackquack() / 什么都不做,叫Squeakquack() / 橡皮鴨子吱吱叫Quackquack() / 實(shí)現(xiàn)鴨子呱呱叫FlyNoWayfly() / 什么都不做,飛FlyWithWingsfly() / 實(shí)現(xiàn)鴨子飛行<<interface>>QuackB

18、ehaviorquack()<<interface>>FlyBehaviorfly()類中的行為問:我是不是一定要先把系統(tǒng)做出來,再看看有哪些地方需要變化,然后才回頭去把這些地方分離&封裝? 問:用一個(gè)類代表一個(gè)行為,感覺似乎有點(diǎn)奇怪。類不是應(yīng)該代表某種東西嗎?類不是應(yīng)該同時(shí)具備狀態(tài)與行為? 答:不盡然。通常在你設(shè)計(jì)系統(tǒng)時(shí),預(yù)先考慮到有哪些地方未來可能需要變化,于是提前在設(shè)計(jì)上加入這答:在OO系統(tǒng)中,是的,類代表的是東西,有狀態(tài)( 些彈性。你會(huì)發(fā)現(xiàn),原則與模式適合使用在開發(fā)實(shí)例變量),也有。只是在本范例中,碰巧東過的任何階段。西是個(gè)行為。但是即使是行為,也仍然可

19、以有狀態(tài)和,例如,飛行的行為可以具有實(shí)例變量, 飛行行為的屬性(每秒翅膀拍動(dòng)幾下、最大高度、速度.等)。問:Duck是不是也該設(shè)計(jì)成一個(gè)接口? 答:在本范例中,這么做并不恰當(dāng)。如你所見的,我們已經(jīng)讓一切都整合妥當(dāng),而且讓Duck成為一個(gè)具體類,如此可以讓衍生的特定類(例如綠頭鴨)具有Duck共同的屬性和。我們已經(jīng)將變化之處移到Duck的外面,原先的問題都已經(jīng)解決了,所以不需要把Duck設(shè)計(jì)成接口。14第一章削尖你的鉛筆1 在我們的新設(shè)計(jì)中,如果你要加上一個(gè)火箭動(dòng)力的飛行動(dòng)作到SimUDuck 系統(tǒng)中,你該怎么做? 2 除了鴨子之外,你能夠想出有什么類會(huì)需要用到行為? 介紹設(shè)計(jì)模式整合鴨子的行為

20、關(guān)鍵在于,鴨子現(xiàn)在會(huì)將飛行和呱呱叫的動(dòng)作,委托(delegate)別人處理,而不是使用定義在類(或子類)內(nèi)的。作法是這樣的: 1首先,在鴨子中加入兩個(gè)實(shí)例變量,分別為flyBehavior與quackBehavior, 為接口類型(而不是具體類實(shí)現(xiàn)類型),每個(gè)變量會(huì)利用多態(tài)的方式在運(yùn)行時(shí)Squeak.等)。正確的行為類型(例如:FlyWithWings、我們也必須將Duck類與其所有子類中的fly() 與quack() 移除,因?yàn)檫@些行為已經(jīng)被搬移到FlyBehavior 與Quackehavior 類中了。我們用performFly() 和performQuack() 取代Duck類中的fl

21、y() 與quack()。稍后你就知道為什么。鴨子行為 2現(xiàn)在,我們來實(shí)現(xiàn)performQuack(): public class Duck QuackBehavior quackBehavior;/ 還有public void performQuack() quackBehavior.quack();很容易,是吧?想進(jìn)行呱呱叫的動(dòng)作,Duck 對(duì)象只要叫quackBehavior 對(duì)象去呱呱叫就可以了。在這部分的代碼中,我們不在乎QuackBehavior 接口的對(duì)象到底是什么,我們只關(guān)心該對(duì)象知道如何進(jìn)行呱呱叫就夠了。目前位置 15DuckFlyBehavior flyBehavior Q

22、uackBehavior quackBehaviorperformQuack()swim() display() performFly()/ 鴨子的其他.整合鴨子的行為的整合3好吧!現(xiàn)在來關(guān)心如何設(shè)定flyBehavior quackBehavior的實(shí)例變量??纯碝allardDuck類: 與public class MallardDuck extends Duck public MallardDuck() quackBehavior = new Quack(); flyBehavior = new FlyWithWings();public void display() System.ou

23、t.println(“Im a real Mallard duck”);所以,綠頭鴨會(huì)真的呱呱叫,而不是吱吱叫,或叫不出聲。這是怎么辦到的?當(dāng)MallardDuck對(duì)象產(chǎn)生時(shí),它的構(gòu)造器會(huì)把繼承來的quackBehavior 實(shí)例變量予以初始化成Quack 類型的新實(shí)例(Quack是QuackBehavior 的具體實(shí)現(xiàn)類)。同樣的處理方式也可以用在飛行行為上:MallardDuck的構(gòu)造器將flyBehavior 實(shí)例變量初始化成FlyWithWings 類型的實(shí)例( FlyWithWings 是FlyBehavior 的具體實(shí)現(xiàn)類)。16第一章別忘了,因?yàn)镸allardDuck繼 Duck

24、類,所以具有flyBehavior 與 qua ckBehavior 實(shí)例變量。介紹設(shè)計(jì)模式別忘了,因?yàn)镸allardDuck繼Duck類,所以具有flyBehavior 與 quac kBehavior 實(shí)例變量。給你逮到了,我們的確是這么做.只是暫時(shí)。稍后在書中,我們的工具箱會(huì)有的模式可用,到時(shí)候就可以這一點(diǎn)了。仍請(qǐng)注意,雖然我們把行為設(shè)定成具 體的類(通過實(shí)例化類似Quack 或FlyWithWings的行為類,并指定到行為引用變量中),但是還是可以在運(yùn)行時(shí)輕易地改變?cè)撔袨椤K裕壳暗淖鞣ㄟ€是很有彈性的,只是初始化實(shí)例變量的作法不夠彈性罷了。但是想,因?yàn)閝uackBehavior 實(shí)例

25、變量是一個(gè)接口類型,能夠在運(yùn)行時(shí),透過多態(tài)的魔法動(dòng)態(tài)地指定不同的QuickBehavior 實(shí)現(xiàn)類給它。想想,如何實(shí)現(xiàn)鴨子,好讓其行為可以在運(yùn)行時(shí)改變。(再幾頁以后,你就會(huì)看到進(jìn)行這件事的代碼。) 目前位置 17測(cè)試?guó)喿拥男袨闇y(cè)試Duck的代碼輸入下面的Duck類(Duck.java)以及兩頁前的MallardDuck類( MallardDuck.java),并編譯之。1public abstract class Duck FlyBehavior flyBehavior; QuackBehavior quackBehavior;publicDuck() publicabstract void

26、display();publicvoid performFly() 委托給行為類flyBehavior.fly();public void performQuack() quackBehavior.quack();public void swim() System.out.println(“Allducks float, even decoys!”);2輸入FlyBehavior 接口(FlyBehavior.java)與兩個(gè)行為實(shí)現(xiàn)類( FlyWithWings.java 與FlyNoWay.java),并編譯之。public interface FlyBehavior public voi

27、d fly();public class FlyWithWings implements FlyBehavior public void fly() System.out.println(“Im flying!”);public class FlyNoWay implements FlyBehavior public void fly() System.out.println(“I cant fly”);第一章18介紹設(shè)計(jì)模式繼續(xù)測(cè)試Duck的代碼 . 3輸入QuackBehavior 接口(QuackBehavior.java)及其三個(gè)實(shí)現(xiàn)類( Quack.java、MuteQuack.ja

28、va、Squeak.java),并編譯之。public interface QuackBehavior public void quack();public class Quack implements QuackBehavior public void quack() System.out.println(“Quack”);public class MuteQuack implements QuackBehavior public void quack() System.out.println(“<< Silence >>”);public class Squeak

29、implements QuackBehavior public void quack() System.out.println(“Squeak”);4輸入并編譯測(cè)試類(MiniDuckSimulator.java) public class MiniDuckSimulator public static void main(String args) Duck mallard = new MallardDuck(); mallard.performQuack(); mallard.performFly();5運(yùn)行代碼! 目前位置 19File Edit Window Help Yadayaday

30、ada%java MiniDuckSimulator QuackIm flying!具有動(dòng)態(tài)行為的鴨子動(dòng)態(tài)地設(shè)定行為在鴨子里建立了一堆動(dòng)態(tài)的功能沒有用到,就太可惜了!假設(shè)我們想在類透過設(shè)定(setter method)設(shè)定鴨子的行為,而不是在鴨子的構(gòu)造器內(nèi)實(shí)例化。1在Duck類中,加入兩個(gè)新:public void setFlyBehavior(FlyBehavior fb) flyBehavior = fb;public void setQuackBehavior(QuackBehavior qb) quackBehavior = qb;從此以后,我們可以隨時(shí)調(diào)用這兩個(gè)為。改變鴨子的行一個(gè)新

31、的鴨子類型:模型鴨(M Duck.java) 2public class MDuck extendsDuck public MDuck() flyBehavior = new FlyNoWay();quackBehavior = new Quack();public void display() System.out.println(“Im a mduck”);建立一個(gè)新的FlyBehavior 類型( FlyRocketPowered.java) 3public class FlyRocketPowered implements FlyBehavior public void fly() S

32、ystem.out.println(“Im flying with a rocket!”);20第一章DuckFlyBehavior flyBehavior; QuackBehavior quackBehavior;swim()display() performQuack() performFly() setFlyBehavior() setQuackBehavior()/ 鴨子的其他介紹設(shè)計(jì)模式改變測(cè)試類(MiniDuckSimulator.java),加上模型鴨,并改變前讓模型鴨具有火箭動(dòng)力。4改變前public class MiniDuckSimulator public static

33、void main(String args) Duck mallard = new MallardDuck(); mallard.performQuack(); mallard.performFly();5運(yùn)行! File Edit Window Help Yabadabadoo改變后在運(yùn)行時(shí)想改變鴨子的行為,只要調(diào)用鴨子的setter就可以。目前位置 21%java MiniDuckSimulator QuackIm flying! I cant flyIm flying with a rocket!Duck m= new MDuck(); m.performFly();m.setFlyBe

34、havior(new FlyRocketPowered(); m.performFly();大局觀行為封裝的大局觀好,我們已經(jīng)深入鴨子模擬器的設(shè)計(jì),該是將頭探出水面,呼吸空氣的時(shí)候了?,F(xiàn)在就來看看整體的格局。下面是整個(gè)重新設(shè)計(jì)后的類架構(gòu),你所期望的一切都有:鴨子繼 Duck,飛行行為實(shí)現(xiàn)FlyBehavior QuackBehavior 接口。接口,呱呱叫行為實(shí)現(xiàn)也請(qǐng)注意,我們敘述事情的方式也稍有改變。不再把鴨子的行為說成一組行為,我們開始把行為想成是一群算法。想想看,在SimUDuck 的設(shè)計(jì)中,算法代表鴨子能做的事(不同的叫法和飛行法), 這樣的作法,似乎也能套用在他處,例如:用一群實(shí)現(xiàn)相

35、同接口的類, 每個(gè)類實(shí)現(xiàn)不同的營(yíng)業(yè)稅計(jì)算公式,就可以算出不同的稅金。請(qǐng)?zhí)貏e注意類之間的。拿一枝筆,把下面圖形中的每個(gè)箭頭標(biāo)上適當(dāng)?shù)?,以是IS -A(是一個(gè))、HAS-A(有一個(gè))、IMPLEMENTS(實(shí)現(xiàn))。22第一章封裝呱呱叫行為MuteQuackquack() / 什么事都不做, 叫! Squeakquack() / 橡皮鴨吱吱叫Quackquack) / 實(shí)現(xiàn)鴨子呱呱叫<<interface>>QuackBehaviorquack()客戶DecoyDuckdisplay() / 看起來像誘餌鴨 RubberDuckdisplay() / 看起來像橡皮鴨 Redh

36、eadDuckdisplay() / 看起來像紅頭鴨 MallardDuckdisplay() / 看起來像綠頭鴨 DuckFlyBehavior flyBehavior QuackBehavior quackBehaviorswim()display() performQuack() performFly() setFlyBehavior() setQuackBehavior()/ 鴨子的其他行為.封裝飛行行為FlyNoWayfly() / 什么事都不做, 飛! FlyWithWingsfly() / 實(shí)現(xiàn)鴨子的飛行<<interface>>FlyBehaviorfl

37、y()介紹設(shè)計(jì)模式有一個(gè)可能比是一個(gè)更好。有一個(gè)相當(dāng)有趣:每一鴨子都有一個(gè) FlyBehavior且有一個(gè)QuackBehavior,讓行和呱呱叫委托它們代為處理。飛大師與門徒. 當(dāng)你將兩個(gè)類結(jié)合起來使用,如同本例,這就是組大師:蚱蜢,告訴我, 在面向?qū)ο蟮牡溃希╟omposition)。這種作法和繼承不同的地方在于,鴨子的行為不是繼承而來,而是和適當(dāng)?shù)男袨閷?duì)象組合而來。你學(xué)到了什么? 門徒:大師,我學(xué)到了,面向?qū)ο筮@是一個(gè)很重要的技巧。其實(shí)是使用了我們的第三個(gè)設(shè)計(jì)原則: 之路,可以復(fù)用。大師:繼續(xù)說. 門徒:大師,藉由繼承,好東西可以一再被利用,所以程序開發(fā)時(shí)間就會(huì)大幅減少,就好像在林中很

38、快地把竹子截短一樣。設(shè)計(jì)原則多用組合,少用繼承。大師:蚱蜢呀! 開發(fā)完成前如你所見,使用組合建立系統(tǒng)具有很大的彈性,不僅可將算法族封裝成類,更可以在運(yùn)行時(shí)動(dòng)態(tài)地改變行為,只要組合的行為對(duì)象,符合正確的接口標(biāo)準(zhǔn)即可。以及完成后,何者需要花費(fèi)更多時(shí)間呢? 門徒: 是后,大師。我們總是需要花許多時(shí)間在系統(tǒng)的維護(hù)和變化上,比原先開發(fā)花的時(shí)間更多。組合用在許多設(shè)計(jì)模式中, 它的諸多優(yōu)點(diǎn)和缺點(diǎn)。中,你也會(huì)看到大師,我說蚱蜢,這就對(duì)啦!那么我們是不是應(yīng)該致力于提高可維護(hù)性和可擴(kuò)充性上的復(fù)用程度呀? 門徒:是的,大師,的確是如此。大師:我覺得你還有很多東西要學(xué), 希望你再深入研究繼承。你會(huì)發(fā)現(xiàn), 繼承有它的問

39、題,還有一些其他的方式可以達(dá)到復(fù)用。目前位置 23鴨(duckcall)是一種裝置,獵人用鴨出鴨,以引誘野鴨。你如何實(shí)現(xiàn)你的鴨,而不繼Duck類? 策略模式講到設(shè)計(jì)模式 恭喜你,學(xué)會(huì)第一個(gè)模式了! 你剛剛用了你的第一個(gè)設(shè)計(jì)模式:也就是策略模式(Strategy Pattern)。不要懷疑,你正是使用策略模式改寫SimUDuck 程序的。感謝這個(gè)模式,現(xiàn)在系統(tǒng)不擔(dān)心遇到任何改變,主管們可以到賭城狂歡。為了這個(gè)模式,我們走了很長(zhǎng)的一段路。下面是此模式的正式定義: 24第一章策略模式定義了算法 ,分別封裝起來,讓它們之間可以互相替換,此模式讓算法的變化, 影響到使用算法的客戶。介紹設(shè)計(jì)模式設(shè)計(jì)謎題在

40、下面,你將看到一堆雜亂的類與接口,這是取自一個(gè)交互式的游戲。你將看到代表游戲角色的類,以及行為的類。每個(gè)角色一次只能使用一個(gè),但是可以在游戲的過換。你的工作是要弄清楚這一切. (在本章末) 你的任務(wù): 11.22.33.安排類。找出一個(gè)抽象類、一個(gè)接口、以及八個(gè)類。在類之間畫箭頭。a. 繼承就畫成這樣(extend)。b. 實(shí)現(xiàn)接口就畫成這樣(implement)。c. 有一個(gè)就畫成這樣。44.把setWeapon() 放到正確的類中。CharacterWeaponBehavior weapon;fight();BowAndArrowBehaviorKnifeBehavioruseWeapon

41、() / 實(shí)現(xiàn)用useWeapon() / 實(shí)現(xiàn)用弓箭刺殺 射擊 <<interface>>QueenWeaponBehaviorfight() . useWeapon();KingAxeBehaviorfight() . TrolluseWeapon() / 實(shí)現(xiàn)用斧頭砍劈 fight() . KnightSwordBehaviorfight() . useWeapon() / 實(shí)現(xiàn)用寶劍揮舞 目前位置 25setWeapon(WeaponBehavior w) this.weapon = w;餐廳在附近餐廳中無意間聽到. Flo 我要一份涂了奶酪以及果醬的白面包、加

42、了香草冰淇淋的巧克力汽水、夾了的火烤起司三明治、鮪魚給我一份C.J.白的, 一個(gè)黑與白,一份尼,一份Radio,一份主廚船, 一個(gè)普通咖啡,還有給我燒一個(gè)!色拉土司、香蕉船(有冰淇淋和香蕉片)、一杯加了奶精和兩顆糖的咖啡.嗯. 還有一個(gè)燒烤漢堡!這兩人點(diǎn)的餐有何不同?其實(shí)沒有差異,其實(shí)都是一份單,只是倍,而且快餐店的廚師已經(jīng)感到不耐煩了。的長(zhǎng)度多了一什么是Flo有的,而沒有? 是,F(xiàn)lo和廚師之間有共享的詞匯, 卻不懂這些詞匯。共享的詞匯不僅方便顧客點(diǎn)餐,也讓廚師不用記太多事,畢竟這些餐點(diǎn)模式都已經(jīng)在他的腦海中了呀! 設(shè)計(jì)模式讓你和其他開發(fā)之間有共享的詞匯,一旦懂這些詞匯,和其他開發(fā)之間這些觀

43、念就很容易,也會(huì)激起那些不懂的程序員想開始學(xué)習(xí)設(shè)計(jì)模式。設(shè)計(jì)模式也可以幫助你提升思考架構(gòu)的層次到模式層面,而不是停留在瑣碎的對(duì)象上。26第一章介紹設(shè)計(jì)模式在辦公室隔間中無意間聽到. 我建立了這一個(gè)廣播類, 能夠追蹤所有的對(duì)象,只 要有新資料進(jìn)來,就會(huì)通知每個(gè)者。最棒的是,者可以隨時(shí)加入此廣播系統(tǒng), 甚至可以隨時(shí)將從系統(tǒng)中移除。如此的設(shè)計(jì)方式相當(dāng)?shù)膭?dòng)態(tài),對(duì)象之間的依賴程度也會(huì)降低。Rick 沒錯(cuò),如果 你 用 模Rick,你只要 說使用了觀察者模式我們就懂了。式名稱和大家,其他開發(fā)能夠馬上且清楚地知道你在說些什么。但是也請(qǐng)不要從此染上模式瘋.以后連寫一個(gè)HelloWorld都能夠扯上模式,那就代

44、表你已經(jīng)病了.目前位置 27除了面向?qū)ο笤O(shè)計(jì)和在餐廳點(diǎn)餐之外, 你還能夠想到有那些例子是需要共享的詞匯?(暗示想汽修、木工、料理、航管)利用這些專業(yè)術(shù)語的質(zhì)量如何? 你能否想到有什么OO設(shè)計(jì)上的東西,能夠和模式名稱匹配的?利用策略模式這個(gè)名字是否傳神? 共通詞匯共享模式詞匯的你使用模式和他人享術(shù)語而已。,其實(shí)不只是和他人共共享的模式詞匯強(qiáng)大。當(dāng)你使用模式名稱和其他開發(fā)或者開發(fā)團(tuán)隊(duì)時(shí),你們之間交流的不只是模式名稱,而是一整套模式背后所象征的質(zhì)量、特性、約束。模式能夠讓你用更少的詞匯做更充分的當(dāng)你用模式描述的時(shí)候,其他開發(fā)你對(duì)設(shè)計(jì)的想法。便很容易地知道將說話的方式保持在模式層次,可讓你待在設(shè)計(jì)圈子

45、久一點(diǎn)。使用模式談?wù)撓到y(tǒng),可以讓你保持在設(shè)計(jì)層次,不會(huì)被壓低到對(duì)象與類這種瑣碎的事情上面。共享詞匯可幫你的開發(fā)團(tuán)隊(duì)快速充電。對(duì)于設(shè)計(jì)模式有深入了解的團(tuán)隊(duì),彼此之間對(duì)于設(shè)計(jì)的看法不容易產(chǎn)生誤解。共享詞匯能幫助初級(jí)開發(fā)迅速成長(zhǎng)。初級(jí)開發(fā)向有經(jīng)驗(yàn)的開發(fā)看齊。當(dāng)高級(jí)開發(fā)人員使用設(shè)計(jì)模式,初級(jí)開發(fā)也會(huì)有樣學(xué)樣。把你的組織建立成一個(gè)模式用戶的社區(qū)。28第一章介紹設(shè)計(jì)模式我如何使用設(shè)計(jì)模式? 我們?nèi)际褂脛e人設(shè)計(jì)庫與框架。我們討論庫與框架、利用它們的API 編程、編譯成我們的程序、享受運(yùn)用別人的代碼所帶來的優(yōu)點(diǎn)??纯碕ava API 以及它所帶來的功能:網(wǎng)絡(luò)、GUI、IO,等等。庫與框架長(zhǎng)久以來,一直扮演著

46、開發(fā)過程的重要角色,我們從中挑選所要的組件,把它們放進(jìn)正確的地方。但是.庫與框架無法幫助構(gòu),所以需要設(shè)計(jì)模式。應(yīng)用組織成容易了解、容易維護(hù)、具有彈性的架設(shè)計(jì)模式直接進(jìn)入你的代碼中,而是必須先進(jìn)入你的腦袋中。一旦你先在腦海中裝入許多模式的知識(shí),就能夠開始在新設(shè)計(jì)中采用它們,以及當(dāng)你的舊代碼變得如同意大利面一樣攪和成一團(tuán)沒彈性時(shí),可用它們改寫代碼。許多模式問:如果設(shè)計(jì)模式這么棒,為何沒有人建立相關(guān)的庫,我們就不問:庫和框架不也是設(shè)計(jì)模式嗎? 問:那么,沒有所謂設(shè)計(jì)模式的庫? 必動(dòng)手了? 答:庫和框架提供了我們某些特定的實(shí)現(xiàn),讓我們的代碼可以輕答:沒錯(cuò),但是稍后你會(huì)看到設(shè)答:設(shè)計(jì)模式比庫的等級(jí)更高。

47、設(shè)計(jì)模式告訴我們?nèi)绾谓M織類和對(duì)象,以解決某類型的問題。采納這些設(shè)計(jì)并使它們適合我們自己的應(yīng)用,是我們責(zé)無旁貸的事。計(jì)模式列表。你可以在應(yīng)用易地,但是這并不算是設(shè)計(jì)中利用這些設(shè)計(jì)模式。模式。有些時(shí)候,庫和框架本身會(huì)用到設(shè)計(jì)模式,這樣很好,因?yàn)橐坏┠懔私饬嗽O(shè)計(jì)模式,會(huì)更容易了解這些API 是模式構(gòu)造的。著設(shè)計(jì)目前位置 29Object thatOBSERVERholds state888Oint88ObAutomatic update/notification Observers 為何要用設(shè)計(jì)模式? 模式只不過是利用 OO設(shè)計(jì)原則.這是常見的錯(cuò)誤觀 念,蚱蜢,事實(shí)比這微妙得多,你還有許多東西要學(xué).

48、懷疑的開發(fā)友善的模式大師開發(fā):好吧!但是不都只是面向?qū)ο笤O(shè)計(jì)嗎?我是說,我懂得運(yùn)用封裝、抽象、繼承、多態(tài), 的還有必要用設(shè)計(jì)模式思考嗎?運(yùn)用OO,一切不是都很直覺嗎?這不正是我過去上了一堆OO 課程的嗎?我認(rèn)為設(shè)計(jì)模式只對(duì)那些不懂OO 設(shè)計(jì)的人有用。大師:這是面向?qū)ο箝_發(fā)常有的謬誤:以性的、可復(fù)用的、可維護(hù)的系統(tǒng)。OO 基礎(chǔ)概念,就能自動(dòng)設(shè)計(jì)出彈開發(fā):不是這樣嗎? 大師:不是!要構(gòu)造OO 系統(tǒng)不光只有懂這些觀念就可以,事實(shí)證明只有透過不斷地艱苦實(shí)踐,才能。開發(fā):我開始了解了,這些構(gòu)造OO 系統(tǒng)的經(jīng)驗(yàn)于是被整理出來. 大師:.是的,被整理成了一群設(shè)計(jì)模式。開發(fā):那么,如果知道了這些模式,我就可以

49、減少許多體力勞動(dòng),直接采用可行的模式。大師:對(duì)的,可以這么說。不過要記得,設(shè)計(jì)是一種藝術(shù),總是有許多取舍的地方。但是如果你能采用這些經(jīng)過深思熟慮,且通過時(shí)間考驗(yàn)的設(shè)計(jì)模式,你就領(lǐng)先別人了。30第一章介紹設(shè)計(jì)模式記住,知道抽象、繼承、多態(tài)這些概念,并馬上讓你變成面向?qū)ο笤O(shè)計(jì)者。設(shè)計(jì)大師關(guān)心的是建立彈性的設(shè)計(jì),可以維護(hù), 可以應(yīng)付改變。開發(fā):如果我找不到模式,怎么辦? 大師:有一些面向?qū)ο笤瓌t,適用于所有的模式。當(dāng)你無法找到適當(dāng)?shù)哪J浇鉀Q問題時(shí),采用這些原則可以幫助你。開發(fā):原則?你是說除了抽象、封裝. 之外, 還有其他? 大師:是的,建立可維護(hù)的OO 系統(tǒng),要訣就在于隨時(shí)想到系統(tǒng)以后可能需要的變化,現(xiàn)在要如何設(shè)計(jì),以應(yīng)付以后的變化。目前位置 31你的設(shè)計(jì)工具箱設(shè)計(jì)工具箱內(nèi)的工具你幾乎快要讀完第一章了!你已經(jīng)在你的設(shè)計(jì)工具箱內(nèi)放進(jìn)了幾樣工具,在我們進(jìn)入第二章之前, 先將這些工具一一列出。要點(diǎn)32第一章 知道OO 基礎(chǔ),并不足以讓你設(shè)計(jì)出良 OO系統(tǒng)。 良 OO 設(shè)計(jì)必須具備可復(fù)用、可擴(kuò)充、可維護(hù)三個(gè)特性。 模式可以讓我們構(gòu)造出具有良好OO 設(shè)計(jì)質(zhì)量的系統(tǒng)。 模式被認(rèn)為是OO

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論