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

下載本文檔

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

文檔簡介

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

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

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

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

5、知所有鴨子的全部行為。E. 鴨子不能同時又飛又叫。F. 改變會牽一發(fā)動全身,造成其他鴨子不想要的改變。目前位置 A. 代碼在多個子類中重復(fù)。B. 運行時的行為不容易改變。C. 我們不能讓鴨子跳舞。5DecoyDuckquack() / 覆蓋,變成什么事都不做display() / 誘餌鴨 fly() / 覆蓋,變成什么事都不做RubberDuckquack() / 吱吱叫 display() / 橡皮鴨 fly() / 覆蓋,變成什么事都不做繼承並非利用接口如何? Joe認識到繼承可能不是一個解決,因為他剛剛拿到來管的備忘錄,希望以后每六個我可以把fly()取出來,放進一個Flyable接口中

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

22、uackBehavior quackBehaviorperformQuack()swim() display() performFly()/ 鴨子的其他.整合鴨子的行為的整合3好吧!現(xiàn)在來關(guān)心如何設(shè)定flyBehavior quackBehavior的實例變量??纯碝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”);所以,綠頭鴨會真的呱呱叫,而不是吱吱叫,或叫不出聲。這是怎么辦到的?當MallardDuck對象產(chǎn)生時,它的構(gòu)造器會把繼承來的quackBehavior 實例變量予以初始化成Quack 類型的新實例(Quack是QuackBehavior 的具體實現(xiàn)類)。同樣的處理方式也可以用在飛行行為上:MallardDuck的構(gòu)造器將flyBehavior 實例變量初始化成FlyWithWings 類型的實例( FlyWithWings 是FlyBehavior 的具體實現(xiàn)類)。16第一章別忘了,因為MallardDuck繼 Duck

24、類,所以具有flyBehavior 與 qua ckBehavior 實例變量。介紹設(shè)計模式別忘了,因為MallardDuck繼Duck類,所以具有flyBehavior 與 quac kBehavior 實例變量。給你逮到了,我們的確是這么做.只是暫時。稍后在書中,我們的工具箱會有的模式可用,到時候就可以這一點了。仍請注意,雖然我們把行為設(shè)定成具 體的類(通過實例化類似Quack 或FlyWithWings的行為類,并指定到行為引用變量中),但是還是可以在運行時輕易地改變該行為。所以,目前的作法還是很有彈性的,只是初始化實例變量的作法不夠彈性罷了。但是想,因為quackBehavior 實例

25、變量是一個接口類型,能夠在運行時,透過多態(tài)的魔法動態(tài)地指定不同的QuickBehavior 實現(xiàn)類給它。想想,如何實現(xiàn)鴨子,好讓其行為可以在運行時改變。(再幾頁以后,你就會看到進行這件事的代碼。) 目前位置 17測試鴨子的行為測試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)與兩個行為實現(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è)計模式繼續(xù)測試Duck的代碼 . 3輸入QuackBehavior 接口(QuackBehavior.java)及其三個實現(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輸入并編譯測試類(MiniDuckSimulator.java) public class MiniDuckSimulator public static void main(String args) Duck mallard = new MallardDuck(); mallard.performQuack(); mallard.performFly();5運行代碼! 目前位置 19File Edit Window Help Yadayaday

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

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”);建立一個新的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è)計模式改變測試類(MiniDuckSimulator.java),加上模型鴨,并改變前讓模型鴨具有火箭動力。4改變前public class MiniDuckSimulator public static

33、void main(String args) Duck mallard = new MallardDuck(); mallard.performQuack(); mallard.performFly();5運行! File Edit Window Help Yabadabadoo改變后在運行時想改變鴨子的行為,只要調(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è)計,該是將頭探出水面,呼吸空氣的時候了?,F(xiàn)在就來看看整體的格局。下面是整個重新設(shè)計后的類架構(gòu),你所期望的一切都有:鴨子繼 Duck,飛行行為實現(xiàn)FlyBehavior QuackBehavior 接口。接口,呱呱叫行為實現(xiàn)也請注意,我們敘述事情的方式也稍有改變。不再把鴨子的行為說成一組行為,我們開始把行為想成是一群算法。想想看,在SimUDuck 的設(shè)計中,算法代表鴨子能做的事(不同的叫法和飛行法), 這樣的作法,似乎也能套用在他處,例如:用一群實現(xiàn)相

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

溫馨提示

  • 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論