軟件設計原則與設計模式_第1頁
軟件設計原則與設計模式_第2頁
軟件設計原則與設計模式_第3頁
軟件設計原則與設計模式_第4頁
軟件設計原則與設計模式_第5頁
已閱讀5頁,還剩211頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

設計原則與設計模式設計模式式的思想想根源是是基本原原則的宏宏觀運用用,本質(zhì)上是是沒有任任何模式式的發(fā)現(xiàn)模式式的人永永遠是大大師,而死守模模式的人人,最多只能能是一個個工匠.2設計模式式DesignPattern設計模式式DesignPattern面向?qū)ο笙笱芯康牡男骂I域域20世紀90年代,面面向?qū)ο笙蠓椒ㄅc與技術在在國內(nèi)軟軟件業(yè)界界十分火火爆,人人們熱衷衷于談論論“對象象”并引引以為榮榮。十多多年來,,人們發(fā)發(fā)表、出出版了無無數(shù)的文文章和書書籍。現(xiàn)現(xiàn)在,該該寫的似似乎都寫寫完了,,沒有新新花樣玩玩了,真真是一片片無聊設計模式式(DesignPattern))及時問世世,面向向?qū)ο髳蹛酆谜邆儌兘K于有有了新的的追求3設計模式式:起源源起源ChristopherAlexander當代著名名建筑大大師加州大學學伯克利利分校建建筑學教教授、環(huán)環(huán)境結構構研究所所所長、、美國藝藝術與科科學院院院士在建筑、、室內(nèi)、、計算機機、家具具設計甚甚至哲學學方面都都卓有建建樹著作:《APatternLanguage》、《TheTimelessWayofBuilding》4設計模式式:起源源Gof((GangOfFour,“四人人幫”)ErichGamma,RichardHelm,RalphJohnson,JohnVlissides1995年出版了了《DesignPatterns:ElementsofReusableObject--OrientedSoftware》》該書確立立了設計計模式這這個術語語,創(chuàng)導導了一種種新的面面向?qū)ο笙笤O計思思潮。從從此,參參與設計計模式研研究的人人數(shù)爆炸炸性地增增長5設計模式式:起源源6設計模式式什么叫模模式?“每一個個模式描描述了在在我們周周圍不斷斷重復發(fā)發(fā)生的問問題,以以及該問問題的解解決方案案的核心心。這樣樣,你就就能一次次又一次次地使用用該解決決方案而而不必重重復勞動動”盡管軟件件技術發(fā)發(fā)展非常???,但但是仍然然有非常常多的設設計模式式可以讓讓我們套套用設計模式式可以幫幫助人們們簡便地地復用以以前成功功的設計計方案,,提高工工作效率率7設計模式式:研究究現(xiàn)狀設計模式式的研究究現(xiàn)狀pattern與Java、C#pattern與組件件技術(如CORBA)pattern與系統(tǒng)統(tǒng)結構pattern與泛型型編程(genericprogramming)相結合其他(例如UML等)8模式的分分類(gof提出的23個)9創(chuàng)建型結構型行為型類FactoryMethodAdapter(類)InterpreterTemplateMethod

對象AbstractFactoryBuilderPrototypeSingletonAdapter(對象)BridgeCompositeDecoratorFacadeFlyweightProxyChainofResponsibilityCommandIteratorMediatorMementoObserverStateStrategyVisitorBridge((橋梁)模式案例有一個叫叫做HuntBird的游戲,,里面需需要表示示各種各各樣的鳥鳥類10Bridge((橋梁)模式最初的設設計11Bridge((橋梁)模式需求變化化:鳥類類要會飛飛12Bridge((橋梁)模式如果增加加一種鳥鳥類“企企鵝”呢呢?13Bridge((橋梁)模式改進方法法:對““飛”使使用多態(tài)態(tài)14Bridge((橋梁)模式改進方法法:再次次使用繼繼承15Bridge((橋梁)模式如果增加加“游泳泳”行為為呢?16Bridge((橋梁)模式繼承只會會使得問問題越來來越復雜雜繼承是面面向?qū)ο笙蟮幕颈痉▽毎“???OO=類+對象象+繼承承+消息息通信17設計原則1:組合優(yōu)先優(yōu)先使用組合,而不是繼承設計原則則:組合合優(yōu)先繼承復用用的優(yōu)點點可以很容容易的修修改或擴擴展父類類的實現(xiàn)現(xiàn)18設計原則則:組合合優(yōu)先繼承復用用的缺點點繼承破壞壞封裝,,因為父父類的實實現(xiàn)細節(jié)節(jié)完全暴暴露給子子類(白盒復用用)父類的實實現(xiàn)發(fā)生生改變,,則子類類必受牽牽連繼承是靜靜態(tài)的,,不能在在運行時時發(fā)生改改變,不不靈活19設計原則則:組合合優(yōu)先組合復用用的優(yōu)點點不破壞封封裝,這這種復用用是黑盒盒復用,,因為成成員對象象的內(nèi)部部細節(jié)對對新對象象保密所需依賴賴少(只依賴接接口)是動態(tài)的的,可以以把成員員對象動動態(tài)替換換為另一一個類型型相同的的對象組合復用用的缺點點對象數(shù)量量會增加加使用委托托(delegation)會使得系系統(tǒng)復雜雜20設計原則則:組合合優(yōu)先組合優(yōu)先先Favorcompositionoverinheritance當需要應應對變化化的時候候,應該該首先使使用組合合的方式式,而不不是繼承承因為組合合更加靈靈活例1:汽車有很很多種,,小轎車車、貨車車、客車車,有的的車是客客貨兩用用,有的的車水陸陸兩用21設計原則則:組合合優(yōu)先如果使用用繼承來來描述::一旦增加加新的汽汽車種類類或用途途,都需需要大量量改動原原有代碼碼22設計原則則:組合合優(yōu)先使用“組組合”思思路考慮慮問題“汽車”擁擁有某種種或某些些“用途途”“汽車””和“用用途”獨獨立變化化,互不不影響23設計原則則:組合合優(yōu)先區(qū)分“Is-A”與“Has--A”有一個系系統(tǒng)需要要描述經(jīng)經(jīng)理、雇雇員和學學生它們都是是人,所所以:24設計原則則:組合合優(yōu)先問題有些人既既是經(jīng)理理,又是是學生,,比如某某位在讀讀MBA的老總25設計原則則:組合合優(yōu)先換一個角角度看問問題雇員、經(jīng)經(jīng)理、學學生其實實都是角角色的一一種人擁有角角色26Bridge((橋梁)模式是什么導導致設計計的不完完美?變化,無無法避免免的、經(jīng)經(jīng)常的需需求變化化設計者的的理想當需求變變化的時時候,盡盡可能少少的修改改代碼就就可以滿滿足新的的需求27設計原則2:封裝可變性發(fā)現(xiàn)代碼容易變化的部分,封裝之,使它和不容易變化的部分獨立開來Bridge((橋梁)模式“發(fā)現(xiàn)變變化點””28Bridge((橋梁)模式“封裝變變化點””變化點1:小鳥一一家29Bridge((橋梁)模式“封裝變變化點””變化點2:鳥類的的行為——飛30Bridge((橋梁)模式“封裝變變化點””變化點2:鳥類的的行為——游泳31Bridge((橋梁)模式“使變化化點和不不變點獨獨立開來來”在這個例例子里其其實是兩兩個變化化點相獨獨立“鳥類””和“行行為”什什么關系系?鳥類擁有行為鳥類行為為的具體體實現(xiàn),,委托““行為””類來完完成32鳥兒擁有有飛、游游泳的行行為33Bridge((橋梁)模式使用橋梁梁模式的的效果比如增加加一種鳥鳥類“鵝鵝”,相相應的要要增加一種游泳泳的行為為“紅掌掌撥清波波”只需要增加一個鳥類類的子類類“鵝””增加一個游泳泳的行為為“紅掌掌撥清波波”設置“鵝鵝”的飛飛翔行為為為“飛飛不起來來”設置“鵝鵝”的游游泳行為為為“紅紅掌撥清清波”原有代碼碼不需要要改動!!34Bridge((橋梁)模式35Bridge((橋梁)模式使用橋梁梁模式的的效果當需求改改變的時時候(增增加動物物或行為為),只只需要簡簡單添加加幾個類類對原有代代碼不需需要改動動保證了代代碼的穩(wěn)穩(wěn)定,提提高了可可維護性性36設計原則3:開-閉原則在設計一個軟件的時候,應當使這個軟件可以在不被修改的前提下擴展Bridge((橋梁)模式結構37Bridge((橋梁)模式意圖將抽象部部分與它它的實現(xiàn)現(xiàn)部分分分離,使使它們都都可以獨獨立地變變化適用性抽象和它它的實現(xiàn)現(xiàn)部分可可以獨立立變化類的抽象象以及它它的實現(xiàn)現(xiàn)都可以以通過生生成子類類的方法法加以擴擴充實現(xiàn)部分分的修改改不會對對客戶產(chǎn)產(chǎn)生影響響.......38Bridge((橋梁)模式應用舉例例1:“小朋朋友畫畫畫”使用蠟筆筆需要大中中小三種種型號每種型號號各有12種顏色共36支39Bridge((橋梁)模式使用毛筆筆:大、中、、小3支毛筆12種顏料40Bridge((橋梁)模式蠟筆和毛毛筆的差差別蠟筆:筆筆和顏色色無法分分離,因因此需要要36種蠟筆毛筆:筆筆和顏色色可以獨獨立選擇擇,因此此只有3+12=15個子類體現(xiàn)了Bridge模式將繼承關關系轉(zhuǎn)換換為組合合關系,,從而降降低了系系統(tǒng)間的的耦合,,減少了了代碼冗冗余41Bridge((橋梁)模式應用舉例例2有一個CAD軟件,可可以畫多多種圖形形同時支持持多套繪繪圖算法法傳統(tǒng)的設設計42Bridge((橋梁)模式應用Bridge模式43Bridge((橋梁)模式分析圖形Shape是一個抽抽象概念念,它可可以有許許多具體體化(變化點1)圖形的顯顯示Drawing是圖形的的實現(xiàn),,它也可可以有許許多套算算法(變化點2)Bridge模式使用用組合代代替繼承承,避免免了復雜雜的繼承承體系,,使得兩兩個變化化點獨立立變化,,互不影影響44設計原則則:開-閉原則、、封裝可可變性“開-閉”原則則BertrandMeyer:““Softwareshouldbeopenforextension,,butclosedformodification”在設計一一個軟件件的時候候,應當當使這個個軟件可可以在不不被修改改的前提提下擴展展解釋已有模塊塊,尤其其是最重重要的抽抽象層模模塊不能能動:保保證穩(wěn)定定性和延延續(xù)性可以擴展展新模塊塊:增加加新行為為,保證證靈活性性45設計原則則:開-閉原則、、封裝可可變性BertrandMeyer對象技術術大師法國工程程院院士士蘇黎世工工學院計計算機系系教授發(fā)明了Eiffel語言和按按契約設設計(DesignbyContract))的思想早年參與與了Z形式語言言的設計計名著《面向?qū)ο笙筌浖嫎嬙臁?6設計原則則:開-閉原則、、封裝可可變性玉帝遵照照“開-閉”原則則維護天天庭秩序序當年孫悟悟空大鬧鬧天空,,向天庭庭發(fā)出挑挑戰(zhàn):““皇帝輪輪流做,,明年到到我家.......只教他搬搬出去,,將天宮宮讓與我我!”太白金星星給玉皇皇大帝建議道::“降一一道招安安圣旨,把把他宣來來上界...與他籍名名在箓...一則不動動眾勞師師,二則收仙仙有道也也。”47設計原則則:開-閉原則、、封裝可可變性分析“不動眾眾勞師””、不破破壞天規(guī)規(guī)就是““閉”收仙有道道就是““開”招安,就就是玉帝帝的“開開-閉”原則則:既讓讓孫悟空空滿意,,又不必必更改天天庭現(xiàn)有有的秩序序48設計原則則:開-閉原則、、封裝可可變性分析現(xiàn)有的天天庭秩序序是系統(tǒng)統(tǒng)的最高高抽象層層弼馬溫這這個職位位只是具具體的實實現(xiàn)層招安的關關鍵就是是不允許許更改現(xiàn)現(xiàn)有的天天庭秩序序,但是是允許將將妖猴納納入到文文武百官官中,從從而擴展展了這一一秩序的的具體實實現(xiàn)49設計原則則:開-閉原則、、封裝可可變性“封裝可可變性原原則”gof:“考慮慮你的設設計中什什么可能能會發(fā)生生變化.......考慮你允允許什么么發(fā)生變變化而不不讓這一一變化導導致重新新設計””Shalloway:“發(fā)現(xiàn)現(xiàn)變化點點,并封封裝之””一種可變變性不應應散落在在代碼的的很多角角落一種可變變性不應應當與另另一種可可變性混混合在一一起50設計原則則:開-閉原則、、封裝可可變性設計模式式對“開開-閉”原則則的支持持比如Bridge橋梁模式式:將抽抽象部分分和實現(xiàn)現(xiàn)部分分分別封裝裝,可以以分別獨獨立變化化51設計原則則:開-閉原則、、封裝可可變性對“開-閉”原則則支持的的不好的的例子java.util..Calendar52java提供的描描述歷法法的抽象象類描述公歷歷的子類我們希望望再派生生出一個個子類,,用于描描述陰歷歷設計原則則:開-閉原則、、封裝可可變性問題:Calendar只定義了了適用于于公歷的的常量和和方法53publicfinalstaticintSUNDAY==1;publicfinalstaticintMONDAY==2;...publicfinalstaticintJANUARY==0;;publicfinalstaticintFEBRUARY==1;;...publicvoidsetFistDayOfWeek(intvalue);;publicintgetFirstDayOfWeek());...設計原則則:開-閉原則、、封裝可可變性問題英文的星星期、月月份名稱稱不符合合中國陰陰歷的叫叫法陰歷以10天為一周周,公歷歷和陰歷歷每月的的天數(shù)也也不同,,所以Calendar關于星期期、月份份的算法法不適合合陰歷總之,Calendar無法容納納中國陰陰歷,因因此不支支持“開開-閉”原則則54Strategy(策略)模式橋梁模式式使得兩個個變化點點的獨立立55設計原則則找出應用用中可能能需要變變化之處處把它們獨獨立出來來不要和那那些不需需要變化化的代碼碼混在一一起56Strategy(策略)模式單獨看飛飛的行為為的實現(xiàn)現(xiàn)策略模式式:封裝裝了一系系列算法法,使得得它們可可以相互互替換效果:算算法可以以獨立變變化57設計原則則針對接口口編程,,而不是是針對實實現(xiàn)編程程58策略模式式-開閉原則則.例-計算價格格PublicclassPart{privatedoublebasePrice;;publicvoidsetPrice(doubleprice)){basePrice==price;}publicdoublegetPrice(){{returnbasePrice;}}59某類方法Publicdoubletotalprice((Part[]]parts){doubletotal==0.0;for((inti=0;;i<parts.length;;i+++){total++=parts[i].getPrice());}returntotal;;}60思考內(nèi)存折扣扣?61方法Publicdoubletotalprice((Part[]]parts){doubletotal==0.0;for((inti=0;;i<parts.length;;i+++){if(parts[I]instanceofMemory)total++=parts[i].getPrice())*0.9;elsetotal++=parts[i].getPrice());}returntotal;;}62思考符合OCP嗎?63方法?PublicclassMemoryextendsPart{publicdoublegetPrice(){{returnbasePrice*0.9;}}64更好的方方法?采用一個個PricePolicy類,通過過對其進進行繼承承以提供供不同的的計價策策略65方法PublicclassPart{privatePricePolicypricePolicy;publicvoidsetPricePolicy(PricePolicypolicy)){pricePolicy==policy;}publicvoidsetPrice(doubleprice)){pricePolicy.setPrice(price));}publicdoublegetPrice(){{returnpricePolicy..getPrice(();}}66價格策略略PublicclassPricePolicy{{privatedoublebasePrice;;publicvoidsetPrice(doubleprice)){basePrice==price;}publicdoublegetPrice(){{returnbasePrice;}}67銷售策略略PublicclassSaleextendsPricePolicy{privatedoublediscount;publicvoidsetDiscount(doublediscount)){this.discount=discount;;}publicdoublegetPrice(){{returnbasePrice*discount;;}}68Strategy(策略):定義所所有支持持的算法法的公共共接口ConcreteStrategy(具體策略略):實現(xiàn)具具體算法法Context(上下文):用一個ConcreteStrategy對象來配配置維護一個個對Strategy對象的引引用可定義一一個接口口來讓Strategy訪問它的的數(shù)據(jù)69階段小結結設計原則則70限制變化化的影響響范圍增加新功功能,要要做到只只增加新新代碼,,而不改改動老代代碼盡量用組組合,而而不是繼繼承組合優(yōu)先先開-閉原則封裝可變變性階段小結結策略模式式使得算法法可以獨獨立變化化使用組合合取代繼繼承,封封裝了可可變性,,保證了了“開-閉”橋梁模式式使得抽象象和實現(xiàn)現(xiàn)獨立變變化避免了兩兩個變化化點的耦耦合71Adapter(適配器)模式例子1:“不合合適的插插座”你的電腦腦的插頭頭是三相相的而墻上的的插座只只有兩相相的插頭和插插座的““接口””不匹配配,怎么么辦?72Adapter(適配器)模式例子2:HuntBird游戲中,,希望增增加一種種鳥類““鴨子””但是發(fā)現(xiàn)現(xiàn)以前有有一個系系統(tǒng)中已已經(jīng)有了了“鴨子子”類,,希望重重用老代代碼73Adapter(適配器)模式新老代碼碼接口不不一致74Adapter(適配器)模式疑問把老代碼碼修改一一下不就就可以了了么?如如下:75Adapter(適配器)模式否定首先,老老代碼不不一定允允許修改改比如可能能根本沒沒有代碼碼,只有有鏈接庫庫其次,修修改代碼碼工作量量可能很很大容易出錯錯還記得““開-閉原則””么76Adapter(適配器)模式應用(對象)適配器模模式實現(xiàn)現(xiàn)接口轉(zhuǎn)轉(zhuǎn)換77Adapter(適配器)模式理解1:接口轉(zhuǎn)轉(zhuǎn)換78客戶(鳥)被適配者(鴨子)適配器請求轉(zhuǎn)換后的請求Adapter(適配器)模式79叫呷呷叫Adapter(適配器)模式理解2:重新包包裝,改改變接口口80Adapter(適配器)模式類適配器器81Adapter(適配器)模式結構對象Adapter82Adapter(適配器)模式結構類Adapter83Adapter(適配器)模式意圖將一個類類的接口口轉(zhuǎn)換成成客戶希希望的另另外一個個接口Adapter模式使得得原本由由于接口口不兼容容而不能能一起工工作的那那些類可可以一起起工作84Adapter(適配器)模式應用舉例例1我們打算算編寫一一個畫圖圖軟件其中畫圓圓形已經(jīng)經(jīng)有了一一個現(xiàn)成成的類但是接口口不同,,不能直直接使用用85Adapter(適配器)模式使用對象象Adapter86Adapter(適配器)模式應用舉例例2缺省適配配模式——“魯達剃度度”凡是和尚尚都應該該如此::87Adapter(適配器)模式但是魯智智深并不不是這樣樣88魯智深::習武(){拳打鎮(zhèn)關關西();大鬧五臺臺山();倒拔垂楊楊柳();火燒瓦官官寺();}Adapter(適配器)模式所以當初初魯達剃剃度時,,眾僧說說:“這個人人形容丑丑惡,相相貌兇頑頑,不可可剃度””89?Adapter(適配器)模式但是長老老卻說::“此人上上應天星星,心地地剛直。。雖然時時下兇頑頑,命中中駁雜,,久后卻卻得清靜靜。證過過非凡,,汝等皆皆不及他他”90Adapter(適配器)模式“天星””就是缺缺省適配配器當你不想想/不能實現(xiàn)現(xiàn)接口的的所有方方法時利用缺省省適配器器類,提提供這些些方法的的缺省實實現(xiàn)從這個類類再派生生出的子子類就可可以不去去實現(xiàn)那那些不想想實現(xiàn)的的方法了了91真實世界界中的適適配器想一想Java語言中不不同版本本中有沒沒有需要要進行適適配的92真實世界界中的適適配器早期java版本中集集合(Collection)類型((例如::Vector,,Stack,,Hashtable)都實現(xiàn)了了一個elements())方法。該該方法返返回一個個Enumeration(枚舉))新版本中中開始使使用Iterator(迭代器器)接口口,這個個接口和和枚舉接接口很像像,但不不同的是是,迭代代器還提提供了刪刪除元素素的能力力。93問題面對遺留留代碼,,這些代代碼會暴暴露出枚枚舉器接接口,但但我們又又希望在在新的代代碼中只只使用迭迭代器。。解決辦法法構造一個個適配器器將枚舉適適配到迭迭代器949596publicclassEnumerationIteratorimplementsIterator{///適配器看看起來就就是一個個Iterator///我們使用用組合的的方式,將枚舉結結合進適適配器中中,用實例變變量記錄錄Enumerationenumeration;publicEnumerationIterator(Enumerationenumeration){{this.enumeration=enumeration;;} ///迭代器的的hasNext其實是委委托給enumeration的hasMoreElements方法publicbooleanhasNext(){{returnenumeration..hasMoreElements();;} ///迭代器的的next其實是委委托給enumeration的nextElement方法publicObjectnext((){{returnenumeration..nextElement((); }//很不幸,我們不能能支持迭迭代器的的remove方法,所以必須須放棄,這里是拋拋出一個個異常publicvoidremove((){{thrownewUnsupportedOperationException((); }}97實例有一個類類(adaptee)實現(xiàn)了數(shù)數(shù)學中的的冪次運運算,方方法中需需要傳入入兩個參參數(shù),一一個是基基數(shù)base,另外一一個是冪冪次exp?,F(xiàn)在客客戶端需需要一個個求得一一個數(shù)的的平方的的函數(shù)接接口(target),傳入一一個數(shù),,得到它它的平方方值。為為了復用用已經(jīng)存存在的類類adaptee,使用Adapter來適配adaptee,adapter實現(xiàn)了target接口。9899在架構層層次上的的應用JDBC驅(qū)動軟件件與適配配器模式式JDBC給出一個個客戶端端通用的的界面。。每個數(shù)數(shù)據(jù)庫引引擎的JDBC驅(qū)動軟件件都是一一個介于于JDBC接口和數(shù)數(shù)據(jù)庫引引擎接口口之間的的適配器器軟件抽象的JDBC接口和各各個數(shù)據(jù)據(jù)庫引擎擎的API之間都需需要相應應的適配配器軟件件,即為為各個數(shù)數(shù)據(jù)庫引引擎準備備的驅(qū)動動軟件。。100JDBC/ODBC橋梁如果沒有有合適的的JDBC驅(qū)動軟件件,用戶戶也可以以通過ODBC驅(qū)動軟件件把JDBC通過一個個JDBC/ODBC橋梁軟件件與ODBC驅(qū)動軟件件連接起起來,從從而達到到連接數(shù)數(shù)據(jù)庫的的目的。。101設計原則則:里氏氏代換原原則例子1:“圓是是不是橢橢圓?””在幾何學學里,圓圓是橢圓圓的一種種特殊情情況因此,把把橢圓看看作父類類,把圓圓作為子子類102設計原則則:里氏氏代換原原則問題橢圓有長長軸、短短軸圓會完全全繼承下下來這些對于于圓來說說毫無意意義類似的::“正方方形不是是矩形””103Circlecircle;circle..GetMajorAxis();;設計原則則:里氏氏代換原原則例子2:“企鵝鵝不是鳥鳥的子類類”凡是鳥都都會飛但是企鵝鵝不會104設計原則則:里氏氏代換原原則例子3我們需要要設計一一個類FileName來描述文文件名,,而文件件名不就就是一個個特殊的的字符串串么?所所以我們們?nèi)绱嗽O設計:105設計原則則:里氏氏代換原原則問題凡是字符符串都支支持相加加操作,,也就是是說兩個個字符串串相加,,結果還還是一個個字符串串可是兩個個文件名名相加,,還是一一個合法法的文件件名么??比如:““c:\a.txt”++““d:\\b.txt””結果是::“c:\a.txtd::\b..txt”106設計原則則:里氏氏代換原原則錯在哪里里?墨子論““取譬””“白馬,,馬也;;乘白馬馬,乘馬馬也。驪驪馬,馬馬也;乘乘驪馬,,乘馬也也?!苯忉專喊装遵R、驪驪馬(黑馬)都是馬,,既然馬馬可以騎騎,那么么白馬和和驪馬肯肯定也可可以騎107設計原則則:里氏氏代換原原則LiskovSubstitutionPrinciple一個軟件件如果使使用的是是一個父父類的話話,如果果把該父父類換成成子類,,它不能能察覺出出父類對對象和子子類對象象的區(qū)別別也就是凡凡是父類類適用的的地方子子類也適適用繼承只有有滿足里里氏代換換原則才才是合理理的108設計原則4:里氏代換原則凡是父類適用的地方子類應當也適用設計原則則:里氏氏代換原原則反過來的的代換不不成立子類適用用的地方方不要求求父類一一定能適適用墨子又說說“娣,美美人也,,愛娣,,非愛美美人也.......盜,人也也,惡盜盜,非惡惡人也””妹妹是美美女,哥哥哥喜歡歡妹妹,,并不是是因為喜喜歡美女女小偷是人人,討厭厭小偷,,并不討討厭所有有人109設計原則則:里氏氏代換原原則Java語言對此此類問題題的防范范它的String類是final的,不能能繼承正確的方方法使用Adapter模式110設計原則則:里氏氏代換原原則Java中的反例例它的Stack類是從Vector類繼承下下來的“棧不就就是施加加了訪問問限制的的數(shù)組么么?”所以“StackIs-AVector”111設計原則則:里氏氏代換原原則用里氏代代換原則則來判斷斷凡是數(shù)組組行得通通的地方方,換成成棧也行行得通么么?Vector可以隨機機訪問,,可以任任意修改改里面的的元素...這些都是是Stack所不允許許的因此Stack不能從Vector繼承下來來,它不不能擁有有Vector的接口112設計原則則:里氏氏代換原原則看看C++STL是怎么辦辦的STL中的stack其實是一一個Adapter113template<classT,classCont=deque<<T>>>classstack{{public:voidpush(constvalue__type&x){c..push_back(x));}}voidpop(){{c..pop_back((x);;}protected:Contc;;};設計模式式-工廠廠模式當看到““new””,就會想想到“具具體”115116一個計算算器例子子publicclassOperation{privatedoublenumberA=0;;privatedoublenumberB=0;;publicvirtualdoubleGetResult(){{doubleresult=0;;returnresult; }}classOperationAdd::Operation{{publicoverridedoubleGetResult()){doubleresult=0;;result==numberA++numberB;returnresult;}當遇到一一群相關關的具體體類時,,通常見見到下面面的代碼碼OperationcreateOperation(Stringoperate){Operationoper;switch((operate){{case”+””:oper=newOperationAdd());break;case”=””:oper=newOperationSub());break;case”*””:oper=newOperationMul());break;……...}}117如果計算算器要增增加更多多的運算算類型怎怎么辦?118簡單工廠廠開始封裝裝創(chuàng)建對對象的代代碼建立一個個簡單工工廠當需要Operation時,就叫叫工廠做做一個119定義簡單單工廠120PublicclassOperationFactory{publicstaticOperationcreateOperate(Stringoperate){{Operationoper=null;switch((operate){{case”+””:oper=newOperationAdd());break;case”=””:oper=newOperationSub());break;case”*””:oper=newOperationMul());break;case”/””:oper=newOperationDiv());break;}returnoper;;}}121簡單工廠廠實現(xiàn)客戶端的的實現(xiàn)Operationoper;oper=OperationFactory.createOperate(“++”);;oper.NumberA==1;oper.NumberB==2;doubleresult=oper.GetResult(();122簡單工廠廠模式的的優(yōu)點123簡單工廠廠類中包包含了必必要的邏邏輯判斷斷,根據(jù)據(jù)客戶端端的選擇擇條件動動態(tài)實例例化相關關的類,,對于客戶戶端來說說,去除除了與具具體產(chǎn)品品的依賴賴。就像計算算器,讓讓客戶端端不用管管該用哪哪個類的的實例,,只要把把‘+’給工廠廠,工廠廠自動就就給出了了實例,,客戶端端只要去去做運算算就可以以了,不不同的實實例會實實現(xiàn)不同同的運算算。簡單工廠廠實現(xiàn)了了責任的的分割。。問題如果要加加一個““求M數(shù)的N此方”的的功能,,就要在在原有方方法中加加一個分分支條件件,就要要修改原原有的類類,違背背了開放-封閉原則,于于是工廠廠方法就就來了。。124定義工廠廠方法模模式工廠方法法模式定定義了一一個創(chuàng)建建對象的的接口由子類決決定實例例化的類類是哪一一個工廠方法法使一個個類的實實例化延延遲到其其子類。。125遵循倒置置依賴原原則的指指導方針針變量不可可以持有有具體類類的引用用如果使用用new,就會持持有具體體類的引引用可以改用用工廠來來避開這這樣的做做法不要讓類類派生自自具體類類如果派生生自具體體類,就就會依賴賴具體類類請派生自自一個抽抽象(接接口或抽抽象類))不是隨時時都要遵遵循這個個原則如直接實實例化字字符串對對象126應用依賴賴倒置原原則要依賴抽抽象,不不要依賴賴具體類類我們把工工廠類抽抽象出一一個接口口,這個個接口只只有一個個方法,,就是創(chuàng)創(chuàng)建抽象象產(chǎn)品的的工廠方方法。然后,所所有的要要生產(chǎn)具具體類的的工廠,,就去實實現(xiàn)這個個接口。。這樣,一一個簡單單工廠模模式的工工廠類,,就變成成了一個個工廠抽抽象接口口和多個個具體生生產(chǎn)對象象的工廠廠。于是,我我們要增增加‘求求M數(shù)的N次方’的的功能時時,就不不需要更更改原有有的工廠廠類了,,只需要要增加此此功能的的運算類類和相應應的工廠廠類就可可以了。。127工廠方法法模式實實現(xiàn)128工廠方法法模式實實現(xiàn)先構建一一個工廠廠接口InterfaceIFactory{OperationCreateOperation();;}129然后加減減乘除各各建一個個具體工工廠去實實現(xiàn)這個個接口classAddFactory:IFactory{publicOperationCreateOperation()){returnnewOperationAdd());}}classSubFactory:IFactory{publicOperationCreateOperation()){returnnewOperationSub());}}130工廠方法法模式實實現(xiàn)然后加減減乘除各各建一個個具體工工廠去實實現(xiàn)這個個接口classMulFactory:IFactory{publicOperationCreateOperation()){returnnewOperationMul());}}classDivFactory:IFactory{publicOperationCreateOperation()){returnnewOperationDiv());}}131工廠方法法模式實實現(xiàn)客戶端的的實現(xiàn)IFactoryoperFactory==newAddFactory();;Operationoper==operFactory.CreateOperation());oper.NumberA==1;oper.NumberB==2;doubleresult=oper.GetResult(();132工廠方法法模式實實現(xiàn)工廠方法法模式實實現(xiàn)時,,客戶端需需要決定定實例化化哪一個個工廠來來實現(xiàn)運運算類,選擇判判斷的問問題還是是存在的的,也就就是說,,工廠方方法把簡簡單工廠廠的內(nèi)部部邏輯判判斷轉(zhuǎn)移移到了客客戶端代代碼來進進行。如果要加加功能,,本來是是改工廠廠類的,,而現(xiàn)在在是修改改客戶端端。133工廠方法法模式一個抽象象產(chǎn)品類類,可以以派生出出多個具具體產(chǎn)品品類。一一個抽抽象工廠廠類,可可以派生生出多個個具體工工廠類。。每個具體體工廠類類只能創(chuàng)創(chuàng)建一個個具體產(chǎn)產(chǎn)品類的的實例。。134工廠方法法模式雷鋒工廠廠雷鋒是眾眾人皆知知的做好好人好事事的模范范。作為一名名大學生生,每個個人都可可以以雷雷鋒做好好事的名名義去幫幫助老人人。在這里,,’雷鋒’類,擁有有掃地、、洗衣、、買米等等方法。。‘學雷鋒鋒的大學學生’類類是‘雷雷鋒’類類的一個個繼承。。而大學生生是要畢畢業(yè)的,,幫助老老人是長長期的,,所以‘‘社區(qū)志志愿者’’更適合合。于是,增增加一個個繼承‘‘雷鋒’’類的‘‘社區(qū)志志愿者’’類。135雷鋒類classLeiFeng{publicvoidSweep()){Console.WriteLine(““掃地”); }publicvoidWash(){{Console.WriteLine(““洗衣”); }publicvoidBuyRice(){{Console.WriteLine(““買米”); }}136大學生類類及社區(qū)區(qū)志愿者者classUndergraduate:LeiFeng{}}classVolunteer::LeiFeng{}}137簡單工廠廠模式ClassSimpleFactory{publicstaticLeiFengCreateLeiFeng(stringtyple)){LeiFengresult==null;;switch((type)){case”學雷鋒的的大學生生”:result==newUndergradute();;break;;case”社區(qū)志愿愿者”:result==newVolunteer());break;}returnresult;}}138客戶端的的實現(xiàn)LeiFengstudentA=SimpleFacatory.CreateLeiFeng(“學雷鋒的的大學生生”);studentA.BuyRice();;LeiFengstudentB=SimpleFacatory.CreateLeiFeng(“學雷鋒的的大學生生”);studentB.Sweep());LeiFengstudentC=SimpleFacatory.CreateLeiFeng(“學雷鋒的的大學生生”);studentC.Wash();;139簡單工廠廠模式在這里,,需要再再任何實實例化的的時候?qū)憣懗鲞@個個工廠的的代碼。。這里有有重復,,于是用用工廠方方法模式式來寫。。140工廠方法法模式InterfaceIFactory{LeiFengCreateLeiFeng(();}classUndergraduteFactory:IFactory{publicLeiFengCreateLeiFeng(){returnnewUndergraduate();;}}141classVolunteerFactory:IFactory{publicLeiFengCreateLeiFeng(){returnnewVolunteer(();}}}客戶端代代碼Ifactoryfactory==newUndergraduateFactory());LeiFengstudentA=factory.CreateLeiFeng();;LeiFengstudentB=factory.CreateLeiFeng();;LeiFengstudentC=factory.CreateLeiFeng();;studentA.BuyRice();;studentB.Sweep());studentC.Wash();;142工廠方法法模式在這里,,盡管如如果要換換成‘社社區(qū)志愿愿者’也也還是要要修改代代碼,但但只用修修改一處處就可以以。工廠方法法克服了了簡單工工廠違背背開放-封閉原則則的缺點點,又保保持了封封裝對象象創(chuàng)建過過程的優(yōu)優(yōu)點。它們都是是集中封封裝了對對象的創(chuàng)創(chuàng)建,使使得要更更換對象象時,不不需要做做大的改改動就可可實現(xiàn),,降低了了客戶程程序與產(chǎn)產(chǎn)品對象象的耦合合。143工廠方法法模式工廠方法法模式是是簡單工工廠模式式的進一一步抽象象和推廣廣,由于于使用了了多態(tài)性性,工廠廠方法模模式保持持了簡單單工廠模模式的優(yōu)優(yōu)點,而而且克服服了它的的缺點。。但缺點是是由于每每加一個個產(chǎn)品,,就需要要加一個個產(chǎn)品工工廠的類類,增加加了額外外了開發(fā)發(fā)量。144工廠方法法模式抽象工廠廠模式提供一個個創(chuàng)建一系列相相關或相相互依賴賴對象的的接口,而無需需指定它它們具體體的類。。145定義抽象象工廠模模式146數(shù)據(jù)訪問問程序用戶類User,假設只只有ID和Name兩個字段段。SqlserverUser類和AccessUser類,用于于操作User表,假設設只有““新增用用戶”和和“得到到用戶””方法。。SqlserverUser類,用于于訪問SQLServer的用戶。。AccessUser類,用于于訪問Access的用戶。。147用工廠方方法模式式的數(shù)據(jù)據(jù)訪問程程序148InterfaceIUser{voidInsert(Useruser);UserGetUser((intid);;}classSqlserverUser:IUser{publicvoidInsert((Useruser){Console.WriteLine(““在SQLServer中給User表增加一一條記錄錄”);}publicvoidGetUser(intid)){Console.WriteLine(““在SQLServer中根據(jù)ID得到User表的一條條記錄”);returnnull;}}149用工廠方方法模式式的數(shù)據(jù)據(jù)訪問程程序classAccessUser:IUser{publicvoidInsert((Useruser){Console.WriteLine(““在Access中給User表增加一一條記錄錄”);}publicvoidGetUser(intid)){Console.WriteLine(““在Access中根據(jù)ID得到User表的一條條記錄”);returnnull;}}150工廠方法法IFactory接口:定義一個個創(chuàng)建訪訪問User表對象的的抽象的的工廠接接口。InterfaceIFactory{IuserCreateUser();;}151SqlServerFactory類,AccessFactory類實現(xiàn)接接口classSqlServerFactory:IFactory{publicIuserCreateUser()){returnnewSqlserverUser();;}}classAccessFactory:IFactory{publicIuserCreateUser()){returnnewAccessUser();;}}152客戶端實實現(xiàn)StaticvoidMain(string[]]args)){Useruser==newUser());Ifactoryfactory=newSqlServerFactory(();Iuseriu==factory..CreateUser());iu.Insert((user);;iu.GetUser(1));Console.Read(();}153用抽象工工廠模式式的數(shù)據(jù)據(jù)訪問程程序154Idepartment接口,用用于客戶戶端訪問問,解除除與具體體數(shù)據(jù)庫庫訪問的的耦合。。interfaceIDepartment{{voidInsert(Departmentdepartment));DepartmentGetDepartment(intid));}SqlserverDepartment類,AccessDepartment類分別用用于訪問問SQLSever、Access的Department。155classSqlserverDepartment:IDepartment{publicvoidInsert((Departmentdepartment){{Console.WriteLine(““在SQLServer中的Department表增加一條條記錄”);}publicDepartmentGetDepartment(intid)){Console.WriteLine(““在SQLServer中根據(jù)ID得到Department表中的一一條記錄錄”);returnnull;}}156classAccessDepartment:IDepartment{publicvoidInsert((Departmentdepartment){{Console.WriteLine(““在Access中的Department表增加一條記錄錄”);}publicDepartmentGetDepartment(intid)){Console.WriteLine(““在Access中根據(jù)ID得到Department表中的一一條記錄錄”);returnnull;}}157interfaceIFactory{IuserCreateUser();;IDepartmentCreateDepartment();;}classSqlServerFactory:IFactory{publicIuserCreateUser()){returnnewSqlserverUser();;}publicIDepartmentCreateDepartment()){returnnewSqlServerDepartment();;}}158classAccessFactory:IFactory{publicIuserCreateUser()){returnnewAccessUser();;}publicIDepartmentCreateDepartment()){returnnewAccessDepartment();;}}159客戶端實實現(xiàn):StaticvoidMain(string[]]args)){Useruser==newUser());Departmentdept==newDepartment());IFactoryfactory=newAccessFactory(();IUseriu==factory..CreateUser());iu.Insert((user);;iu.GetUser(1));Idepartmentid==factory..CreateDepartment());id.Insert((dept);;id.GetDepartment(1));Console.Read(();}160抽象工廠廠模式的的優(yōu)點易于交換換產(chǎn)品系系列,由由于具體體工廠類類在一個個應用中中只需要要在初始始化時出出現(xiàn)一次次,這就就使得改改變一個個應用的的具體工工廠變得得非常容容易,它它只需要要改變具具體工廠廠即可使使用不同同的產(chǎn)品品配置。。它讓具體體的創(chuàng)建建實例過過程與客客戶端分分離,客客戶端是是通過它它們的抽抽象接口口操縱實實例,產(chǎn)產(chǎn)品的具具體類名名也被具具體工廠廠的實現(xiàn)現(xiàn)分離,,不會出出現(xiàn)在客客戶代碼碼中。161抽象工廠廠模式多個抽象象產(chǎn)品類類,每個個抽象產(chǎn)產(chǎn)品類可可以派生生出多個個具體產(chǎn)產(chǎn)品類。。一一個個抽象工工廠類,,可以派派生出多多個具體體工廠類類。每每個具體體工廠類類可以創(chuàng)創(chuàng)建多個個具體產(chǎn)產(chǎn)品類的的實例。。162比較工廠廠方法和和抽象方方法抽象工廠廠的需求求:創(chuàng)建建一個產(chǎn)產(chǎn)品家族族負責在抽抽象工廠廠中創(chuàng)建建產(chǎn)品的的方法,,通常是是以“工工廠方法法”來實實現(xiàn)的163FactoryMethod(工廠方法法)模式例子:““去快餐餐廳吃飯飯”164165voidBuyFood(string餐館,string食品){if(餐館==""KFC"){{if(食品==""Chicken"))hamburger==newKFCChickenHamburger;elseif(food===""Fish"))hamburger==newKFCFishHamburger;}elseif(restaurant===""McDonald""){{if(food===""Chicken"))hamburger==newMcDonaldChickenHamburger;;elseif(food===""Fish"))hamburger==newMcDonaldFishHamburger;;}}FactoryMethod(工廠方法法)模式增加一種種新的食食物呢??166FactoryMethod(工廠方法法)模式傳統(tǒng)設計計的缺點點依賴具體體167voidBuyFood(string餐館,string食品){if(餐館==""KFC"){{if(食品==""Chicken"))hamburger==newKFCChickenHamburger;elseif(food===""Fish"))hamburger==newKFCFishHamburger;}...FactoryMethod(工廠方法法)模式“Abstractionshouldnotdependupondetails..Detailsshoulddependuponabstractions”168設計原則5:依賴倒置原則抽象不應當依賴于細節(jié)細節(jié)應當依賴于抽象設計原則則:依賴賴倒置原原則為什么說說“倒置置”傳統(tǒng)的設設計是抽抽象層依依賴具體體層傳統(tǒng)的重重用,側(cè)側(cè)重于具具體層次次的模塊塊,比如如算法、、數(shù)據(jù)結結構、函函數(shù)庫因此軟件件的高層層模塊依依賴低層層模塊169傳統(tǒng)的依賴方向設計原則則:依賴賴倒置原原則高層依賴賴低層的的問題抽象層包包含的是是系統(tǒng)的的業(yè)務邏邏輯和宏宏觀的、、戰(zhàn)略性性的決定定,是必必然性的的體現(xiàn)具體層則則含有與與實現(xiàn)相相關的算算法和邏邏輯,以以及戰(zhàn)術術性的決決定,帶帶有相當當大的偶偶然性選選擇。具具體層經(jīng)經(jīng)常有變變動,難難免出現(xiàn)現(xiàn)錯誤必然依賴賴偶然,,穩(wěn)定依依賴變動動?170設計原則則:依賴賴倒置原原則依賴具體體的缺點點171設計原則則:依賴賴倒置原原則依賴抽象象抽象一般般不會變變動這樣代碼碼不會受受易變的的具體層層影響172設計原則則:針對對接口編編程如何做到到“依賴賴倒置””?“Programtoaninterface,notanimplementation”173設計原則6:針對接口編程要針對接口編程不要針對實現(xiàn)編程設計原則則:針對對接口編編程“針對接接口編程程”的一一些建議議變量、參參數(shù)、返返回值等等應聲明明為抽象象類不要繼承承非抽象象類不要重載載父類的的非抽象象方法當然這些些只是建建議實際情況況要權衡衡利弊174FactoryMethod(工廠方法法)模式“女媧摶土土造人””《風俗通》:“俗說說天開地地辟,未未有人民民。女媧媧摶黃土土為人。。”175FactoryMethod(工廠方法法)模式簡單工廠廠:根據(jù)傳入入的參數(shù)數(shù),決定定創(chuàng)建哪哪一個產(chǎn)產(chǎn)品類對對象176Human*NvWa::CreateHuman((stringname){{if(name==““ZhangSan"")returnnewZhangSan;elseif(name==““LiSi"))returnnewLiSi;elseif(name===““WangErMaZi"))returnnewWangErMaZi;}FactoryMethod(工廠方法法)模式簡單工廠廠的優(yōu)缺缺點優(yōu)點:實現(xiàn)了責責任分割割利用判斷斷邏輯,,決定實實例化哪哪一個產(chǎn)產(chǎn)品類客戶端可可以免除除直接創(chuàng)創(chuàng)建產(chǎn)品品類對象象的責任任,僅僅僅使用該該產(chǎn)品缺點:沒有完全全做到““開-閉”一旦增加加新的產(chǎn)產(chǎn)品,需需要修改改工廠的的代碼但是客戶戶代碼不不需要修修改“我不入入地獄誰誰入地獄獄”177FactoryMethod(工廠方法法)模式“女媧舉舉繩造人人”“女媧摶摶土為人人,劇務務,力不不暇供,,乃引繩繩于桓泥泥中,舉舉以為人人?!?78FactoryMethod(工廠方法法)模式簡單工廠廠的問題題所有具體體產(chǎn)品對對象的創(chuàng)創(chuàng)建都放放在一個個類中,,一旦增增加新的的產(chǎn)品,,當然工工廠類要要被修改改工廠方法法:使用用多態(tài)來來應對提供一個個抽象工工廠的接接口具體工廠廠分別負負責創(chuàng)建建具體產(chǎn)產(chǎn)品對象象增加新的的產(chǎn)品只只需要相相應增加加新的具具體工廠廠類179FactoryMethod(工廠方法法)模式意圖定義一個個用于創(chuàng)創(chuàng)建對象象的接口口,讓子子類決定定實例化化哪一個個類使一個類類的實例例化延遲遲到其子子類優(yōu)點封裝了創(chuàng)創(chuàng)建具體體對象的的工作使得客戶戶代碼““針對接接口編程程”,保保持對變變化的““關閉””180FactoryMethod(工廠方法法)模式工廠方法法應用到到“快餐餐店”問問題181Fa?ade((門面、外外觀)模式例1:傳統(tǒng)的的醫(yī)院::病人需要要直接跟跟各個部部門打交交道182門診掛號劃價化驗取藥Fa?ade((門面)模式人性化的的醫(yī)院接待員代代替病人人進行掛掛號、劃劃價等病人只需需要和接接待員打打交道183門診掛號劃價取藥接待員醫(yī)院的門門面(Facade)Fa?ade((門面)模式例2:組建家家庭影院院184Fa?ade((門面)模式欣賞一部部電影的的

溫馨提示

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

評論

0/150

提交評論