軟件設(shè)計(jì)原則與設(shè)計(jì)模式課件_第1頁(yè)
軟件設(shè)計(jì)原則與設(shè)計(jì)模式課件_第2頁(yè)
軟件設(shè)計(jì)原則與設(shè)計(jì)模式課件_第3頁(yè)
軟件設(shè)計(jì)原則與設(shè)計(jì)模式課件_第4頁(yè)
軟件設(shè)計(jì)原則與設(shè)計(jì)模式課件_第5頁(yè)
已閱讀5頁(yè),還剩427頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

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

對(duì)象AbstractFactoryBuilderPrototypeSingletonAdapter(對(duì)象)BridgeCompositeDecoratorFacadeFlyweightProxyChainofResponsibilityCommandIteratorMediatorMementoObserverStateStrategyVisitor模式的分類(gof提出的23個(gè))9創(chuàng)建型結(jié)構(gòu)型行為型類Fac9Bridge(橋梁)模式案例有一個(gè)叫做HuntBird的游戲,里面需要表示各種各樣的鳥(niǎo)類10Bridge(橋梁)模式案例1010Bridge(橋梁)模式最初的設(shè)計(jì)11Bridge(橋梁)模式最初的設(shè)計(jì)1111Bridge(橋梁)模式需求變化:鳥(niǎo)類要會(huì)飛12Bridge(橋梁)模式需求變化:鳥(niǎo)類要會(huì)飛1212Bridge(橋梁)模式如果增加一種鳥(niǎo)類“企鵝”呢?13Bridge(橋梁)模式如果增加一種鳥(niǎo)類“企鵝”呢?1313Bridge(橋梁)模式改進(jìn)方法:對(duì)“飛”使用多態(tài)14Bridge(橋梁)模式改進(jìn)方法:對(duì)“飛”使用多態(tài)1414Bridge(橋梁)模式改進(jìn)方法:再次使用繼承15Bridge(橋梁)模式改進(jìn)方法:再次使用繼承1515Bridge(橋梁)模式如果增加“游泳”行為呢?16Bridge(橋梁)模式如果增加“游泳”行為呢?1616Bridge(橋梁)模式繼承只會(huì)使得問(wèn)題越來(lái)越復(fù)雜繼承是面向?qū)ο蟮幕痉▽毎。??OO=類+對(duì)象+繼承+消息通信17設(shè)計(jì)原則1:組合優(yōu)先優(yōu)先使用組合,而不是繼承Bridge(橋梁)模式繼承只會(huì)使得問(wèn)題越來(lái)越復(fù)雜17設(shè)計(jì)原17設(shè)計(jì)原則:組合優(yōu)先繼承復(fù)用的優(yōu)點(diǎn)可以很容易的修改或擴(kuò)展父類的實(shí)現(xiàn)18設(shè)計(jì)原則:組合優(yōu)先繼承復(fù)用的優(yōu)點(diǎn)1818設(shè)計(jì)原則:組合優(yōu)先繼承復(fù)用的缺點(diǎn)繼承破壞封裝,因?yàn)楦割惖膶?shí)現(xiàn)細(xì)節(jié)完全暴露給子類(白盒復(fù)用)父類的實(shí)現(xiàn)發(fā)生改變,則子類必受牽連繼承是靜態(tài)的,不能在運(yùn)行時(shí)發(fā)生改變,不靈活19設(shè)計(jì)原則:組合優(yōu)先繼承復(fù)用的缺點(diǎn)1919設(shè)計(jì)原則:組合優(yōu)先組合復(fù)用的優(yōu)點(diǎn)不破壞封裝,這種復(fù)用是黑盒復(fù)用,因?yàn)槌蓡T對(duì)象的內(nèi)部細(xì)節(jié)對(duì)新對(duì)象保密所需依賴少(只依賴接口)是動(dòng)態(tài)的,可以把成員對(duì)象動(dòng)態(tài)替換為另一個(gè)類型相同的對(duì)象組合復(fù)用的缺點(diǎn)對(duì)象數(shù)量會(huì)增加使用委托(delegation)會(huì)使得系統(tǒng)復(fù)雜20設(shè)計(jì)原則:組合優(yōu)先組合復(fù)用的優(yōu)點(diǎn)2020設(shè)計(jì)原則:組合優(yōu)先組合優(yōu)先Favorcompositionoverinheritance當(dāng)需要應(yīng)對(duì)變化的時(shí)候,應(yīng)該首先使用組合的方式,而不是繼承因?yàn)榻M合更加靈活例1:汽車有很多種,小轎車、貨車、客車,有的車是客貨兩用,有的車水陸兩用21設(shè)計(jì)原則:組合優(yōu)先組合優(yōu)先2121設(shè)計(jì)原則:組合優(yōu)先如果使用繼承來(lái)描述:一旦增加新的汽車種類或用途,都需要大量改動(dòng)原有代碼22設(shè)計(jì)原則:組合優(yōu)先如果使用繼承來(lái)描述:2222設(shè)計(jì)原則:組合優(yōu)先使用“組合”思路考慮問(wèn)題“汽車”擁有某種或某些“用途”“汽車”和“用途”獨(dú)立變化,互不影響23設(shè)計(jì)原則:組合優(yōu)先使用“組合”思路考慮問(wèn)題2323設(shè)計(jì)原則:組合優(yōu)先區(qū)分“Is-A”與“Has-A”有一個(gè)系統(tǒng)需要描述經(jīng)理、雇員和學(xué)生它們都是人,所以:24設(shè)計(jì)原則:組合優(yōu)先區(qū)分“Is-A”與“Has-A”2424設(shè)計(jì)原則:組合優(yōu)先問(wèn)題有些人既是經(jīng)理,又是學(xué)生,比如某位在讀MBA的老總25設(shè)計(jì)原則:組合優(yōu)先問(wèn)題2525設(shè)計(jì)原則:組合優(yōu)先換一個(gè)角度看問(wèn)題雇員、經(jīng)理、學(xué)生其實(shí)都是角色的一種人擁有角色26設(shè)計(jì)原則:組合優(yōu)先換一個(gè)角度看問(wèn)題2626Bridge(橋梁)模式是什么導(dǎo)致設(shè)計(jì)的不完美?變化,無(wú)法避免的、經(jīng)常的需求變化設(shè)計(jì)者的理想當(dāng)需求變化的時(shí)候,盡可能少的修改代碼就可以滿足新的需求27設(shè)計(jì)原則2:封裝可變性發(fā)現(xiàn)代碼容易變化的部分,封裝之,使它和不容易變化的部分獨(dú)立開(kāi)來(lái)Bridge(橋梁)模式是什么導(dǎo)致設(shè)計(jì)的不完美?27設(shè)計(jì)原則27Bridge(橋梁)模式“發(fā)現(xiàn)變化點(diǎn)”28Bridge(橋梁)模式“發(fā)現(xiàn)變化點(diǎn)”2828Bridge(橋梁)模式“封裝變化點(diǎn)”變化點(diǎn)1:小鳥(niǎo)一家29Bridge(橋梁)模式“封裝變化點(diǎn)”2929Bridge(橋梁)模式“封裝變化點(diǎn)”變化點(diǎn)2:鳥(niǎo)類的行為——飛30Bridge(橋梁)模式“封裝變化點(diǎn)”3030Bridge(橋梁)模式“封裝變化點(diǎn)”變化點(diǎn)2:鳥(niǎo)類的行為——游泳31Bridge(橋梁)模式“封裝變化點(diǎn)”3131Bridge(橋梁)模式“使變化點(diǎn)和不變點(diǎn)獨(dú)立開(kāi)來(lái)”在這個(gè)例子里其實(shí)是兩個(gè)變化點(diǎn)相獨(dú)立“鳥(niǎo)類”和“行為”什么關(guān)系?鳥(niǎo)類擁有行為鳥(niǎo)類行為的具體實(shí)現(xiàn),委托“行為”類來(lái)完成32Bridge(橋梁)模式“使變化點(diǎn)和不變點(diǎn)獨(dú)立開(kāi)來(lái)”3232鳥(niǎo)兒擁有飛、游泳的行為33鳥(niǎo)兒擁有飛、游泳的行為3333Bridge(橋梁)模式使用橋梁模式的效果比如增加一種鳥(niǎo)類“鵝”,相應(yīng)的要增加一種游泳的行為“紅掌撥清波”只需要增加一個(gè)鳥(niǎo)類的子類“鵝”增加一個(gè)游泳的行為“紅掌撥清波”設(shè)置“鵝”的飛翔行為為“飛不起來(lái)”設(shè)置“鵝”的游泳行為為“紅掌撥清波”原有代碼不需要改動(dòng)!34Bridge(橋梁)模式使用橋梁模式的效果3434Bridge(橋梁)模式35Bridge(橋梁)模式3535Bridge(橋梁)模式使用橋梁模式的效果當(dāng)需求改變的時(shí)候(增加動(dòng)物或行為),只需要簡(jiǎn)單添加幾個(gè)類對(duì)原有代碼不需要改動(dòng)保證了代碼的穩(wěn)定,提高了可維護(hù)性36設(shè)計(jì)原則3:開(kāi)-閉原則在設(shè)計(jì)一個(gè)軟件的時(shí)候,應(yīng)當(dāng)使這個(gè)軟件可以在不被修改的前提下擴(kuò)展Bridge(橋梁)模式使用橋梁模式的效果36設(shè)計(jì)原則3:開(kāi)36Bridge(橋梁)模式結(jié)構(gòu)37Bridge(橋梁)模式結(jié)構(gòu)3737Bridge(橋梁)模式意圖將抽象部分與它的實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立地變化適用性抽象和它的實(shí)現(xiàn)部分可以獨(dú)立變化類的抽象以及它的實(shí)現(xiàn)都可以通過(guò)生成子類的方法加以擴(kuò)充實(shí)現(xiàn)部分的修改不會(huì)對(duì)客戶產(chǎn)生影響......38Bridge(橋梁)模式意圖3838Bridge(橋梁)模式應(yīng)用舉例1:“小朋友畫(huà)畫(huà)”使用蠟筆需要大中小三種型號(hào)每種型號(hào)各有12種顏色共36支39Bridge(橋梁)模式應(yīng)用舉例1:“小朋友畫(huà)畫(huà)”3939Bridge(橋梁)模式使用毛筆:大、中、小3支毛筆12種顏料40Bridge(橋梁)模式使用毛筆:4040Bridge(橋梁)模式蠟筆和毛筆的差別蠟筆:筆和顏色無(wú)法分離,因此需要36種蠟筆毛筆:筆和顏色可以獨(dú)立選擇,因此只有3+12=15個(gè)子類體現(xiàn)了Bridge模式將繼承關(guān)系轉(zhuǎn)換為組合關(guān)系,從而降低了系統(tǒng)間的耦合,減少了代碼冗余41Bridge(橋梁)模式蠟筆和毛筆的差別4141Bridge(橋梁)模式應(yīng)用舉例2有一個(gè)CAD軟件,可以畫(huà)多種圖形同時(shí)支持多套繪圖算法傳統(tǒng)的設(shè)計(jì)42Bridge(橋梁)模式應(yīng)用舉例24242Bridge(橋梁)模式應(yīng)用Bridge模式43Bridge(橋梁)模式應(yīng)用Bridge模式4343Bridge(橋梁)模式分析圖形Shape是一個(gè)抽象概念,它可以有許多具體化(變化點(diǎn)1)圖形的顯示Drawing是圖形的實(shí)現(xiàn),它也可以有許多套算法(變化點(diǎn)2)Bridge模式使用組合代替繼承,避免了復(fù)雜的繼承體系,使得兩個(gè)變化點(diǎn)獨(dú)立變化,互不影響44Bridge(橋梁)模式分析4444設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性“開(kāi)-閉”原則BertrandMeyer:“Softwareshouldbeopenforextension,butclosedformodification”在設(shè)計(jì)一個(gè)軟件的時(shí)候,應(yīng)當(dāng)使這個(gè)軟件可以在不被修改的前提下擴(kuò)展解釋已有模塊,尤其是最重要的抽象層模塊不能動(dòng):保證穩(wěn)定性和延續(xù)性可以擴(kuò)展新模塊:增加新行為,保證靈活性45設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性“開(kāi)-閉”原則4545設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性BertrandMeyer對(duì)象技術(shù)大師法國(guó)工程院院士蘇黎世工學(xué)院計(jì)算機(jī)系教授發(fā)明了Eiffel語(yǔ)言和按契約設(shè)計(jì)(DesignbyContract)的思想早年參與了Z形式語(yǔ)言的設(shè)計(jì)名著《面向?qū)ο筌浖?gòu)造》46設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性BertrandMeyer46設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性玉帝遵照“開(kāi)-閉”原則維護(hù)天庭秩序當(dāng)年孫悟空大鬧天空,向天庭發(fā)出挑戰(zhàn):“皇帝輪流做,明年到我家......只教他搬出去,將天宮讓與我!”太白金星給玉皇大帝 建議道:“降一道招安 圣旨,把他宣來(lái)上界... 與他籍名在箓... 一則不動(dòng)眾勞師, 二則收仙有道也。”47設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性玉帝遵照“開(kāi)-閉”原則維護(hù)天47設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性分析“不動(dòng)眾勞師”、不破壞天規(guī)就是“閉”收仙有道就是“開(kāi)”招安,就是玉帝的“開(kāi)-閉”原則:既讓孫悟空滿意,又不必更改天庭現(xiàn)有的秩序48設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性分析4848設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性分析現(xiàn)有的天庭秩序是系統(tǒng)的最高抽象層弼馬溫這個(gè)職位只是具體的實(shí)現(xiàn)層招安的關(guān)鍵就是不允許更改現(xiàn)有的天庭秩序,但是允許將妖猴納入到文武百官中,從而擴(kuò)展了這一秩序的具體實(shí)現(xiàn)49設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性分析4949設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性“封裝可變性原則”gof:“考慮你的設(shè)計(jì)中什么可能會(huì)發(fā)生變化......考慮你允許什么發(fā)生變化而不讓這一變化導(dǎo)致重新設(shè)計(jì)”Shalloway:“發(fā)現(xiàn)變化點(diǎn),并封裝之”一種可變性不應(yīng)散落在代碼的很多角落一種可變性不應(yīng)當(dāng)與另一種可變性混合在一起50設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性“封裝可變性原則”5050設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性設(shè)計(jì)模式對(duì)“開(kāi)-閉”原則的支持比如Bridge橋梁模式:將抽象部分和實(shí)現(xiàn)部分分別封裝,可以分別獨(dú)立變化51設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性設(shè)計(jì)模式對(duì)“開(kāi)-閉”原則的支51設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性對(duì)“開(kāi)-閉”原則支持的不好的例子java.util.Calendar52java提供的描述歷法的抽象類描述公歷的子類我們希望再派生出一個(gè)子類,用于描述陰歷設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性對(duì)“開(kāi)-閉”原則支持的不好的52設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性問(wèn)題:Calendar只定義了適用于公歷的常量和方法53publicfinalstaticintSUNDAY=1;publicfinalstaticintMONDAY=2;...publicfinalstaticintJANUARY=0;publicfinalstaticintFEBRUARY=1;...publicvoidsetFistDayOfWeek(intvalue);publicintgetFirstDayOfWeek();...設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性問(wèn)題:53publicfi53設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性問(wèn)題英文的星期、月份名稱不符合中國(guó)陰歷的叫法陰歷以10天為一周,公歷和陰歷每月的天數(shù)也不同,所以Calendar關(guān)于星期、月份的算法不適合陰歷總之,Calendar無(wú)法容納中國(guó)陰歷,因此不支持“開(kāi)-閉”原則54設(shè)計(jì)原則:開(kāi)-閉原則、封裝可變性問(wèn)題5454Strategy(策略)模式橋梁模式使得兩個(gè)變化點(diǎn)的獨(dú)立55Strategy(策略)模式橋梁模式5555設(shè)計(jì)原則找出應(yīng)用中可能需要變化之處把它們獨(dú)立出來(lái)不要和那些不需要變化的代碼混在一起56設(shè)計(jì)原則找出應(yīng)用中可能需要變化之處5656Strategy(策略)模式單獨(dú)看飛的行為的實(shí)現(xiàn)策略模式:封裝了一系列算法,使得它們可以相互替換效果:算法可以獨(dú)立變化57Strategy(策略)模式單獨(dú)看飛的行為的實(shí)現(xiàn)5757設(shè)計(jì)原則針對(duì)接口編程,而不是針對(duì)實(shí)現(xiàn)編程58設(shè)計(jì)原則針對(duì)接口編程,而不是針對(duì)實(shí)現(xiàn)編程5858策略模式-開(kāi)閉原則.例-計(jì)算價(jià)格PublicclassPart{privatedoublebasePrice;publicvoidsetPrice(doubleprice){basePrice=price;}publicdoublegetPrice(){returnbasePrice;}}59策略模式-開(kāi)閉原則.例-計(jì)算價(jià)格PublicclassP59某類方法Publicdoubletotalprice(Part[]parts){doubletotal=0.0;for(inti=0;i<parts.length;i++){total+=parts[i].getPrice();}returntotal;}60某類方法Publicdoubletotalprice(P60思考內(nèi)存折扣?61思考內(nèi)存折扣?6161方法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方法Publicdoubletotalprice(Par62思考符合OCP嗎?63思考符合OCP嗎?6363方法?PublicclassMemoryextendsPart{publicdoublegetPrice(){returnbasePrice*0.9;}}64方法?PublicclassMemoryextends64更好的方法?采用一個(gè)PricePolicy類,通過(guò)對(duì)其進(jìn)行繼承以提供不同的計(jì)價(jià)策略65更好的方法?采用一個(gè)PricePolicy類,通過(guò)對(duì)其進(jìn)行繼65方法PublicclassPart{privatePricePolicypricePolicy;publicvoidsetPricePolicy(PricePolicypolicy){pricePolicy=policy;}publicvoidsetPrice(doubleprice){pricePolicy.setPrice(price);}publicdoublegetPrice(){returnpricePolicy.getPrice();}}66方法PublicclassPart{6666價(jià)格策略PublicclassPricePolicy{privatedoublebasePrice;publicvoidsetPrice(doubleprice){basePrice=price;}publicdoublegetPrice(){returnbasePrice;}}67價(jià)格策略PublicclassPricePolicy{667銷售策略PublicclassSaleextendsPricePolicy{privatedoublediscount;publicvoidsetDiscount(doublediscount){this.discount=discount;}publicdoublegetPrice(){returnbasePrice*discount;}}68銷售策略PublicclassSaleextends68Strategy(策略):定義所有支持的算法的公共接口ConcreteStrategy(具體策略):實(shí)現(xiàn)具體算法Context(上下文):用一個(gè)ConcreteStrategy對(duì)象來(lái)配置維護(hù)一個(gè)對(duì)Strategy對(duì)象的引用可定義一個(gè)接口來(lái)讓Strategy訪問(wèn)它的數(shù)據(jù)69Strategy(策略):定義所有支持的算法的公共接口69階段小結(jié)設(shè)計(jì)原則70限制變化的影響范圍增加新功能,要做到只增加新代碼,而不改動(dòng)老代碼盡量用組合,而不是繼承組合優(yōu)先開(kāi)-閉原則封裝可變性階段小結(jié)設(shè)計(jì)原則70限制變化的影響范圍增加新功能,要做到只增70階段小結(jié)策略模式使得算法可以獨(dú)立變化使用組合取代繼承,封裝了可變性,保證了“開(kāi)-閉”橋梁模式使得抽象和實(shí)現(xiàn)獨(dú)立變化避免了兩個(gè)變化點(diǎn)的耦合71階段小結(jié)策略模式7171Adapter(適配器)模式例子1:“不合適的插座”你的電腦的插頭是三相的而墻上的插座只有兩相的插頭和插座的“接口”不匹配,怎么辦?72Adapter(適配器)模式例子1:“不合適的插座”7272Adapter(適配器)模式例子2:HuntBird游戲中,希望增加一種鳥(niǎo)類“鴨子”但是發(fā)現(xiàn)以前有一個(gè)系統(tǒng)中已經(jīng)有了“鴨子”類,希望重用老代碼73Adapter(適配器)模式例子2:7373Adapter(適配器)模式新老代碼接口不一致74Adapter(適配器)模式新老代碼接口不一致7474Adapter(適配器)模式疑問(wèn)把老代碼修改一下不就可以了么?如下:75Adapter(適配器)模式疑問(wèn)7575Adapter(適配器)模式否定首先,老代碼不一定允許修改比如可能根本沒(méi)有代碼,只有鏈接庫(kù)其次,修改代碼工作量可能很大容易出錯(cuò)還記得“開(kāi)-閉原則”么76Adapter(適配器)模式否定7676Adapter(適配器)模式應(yīng)用(對(duì)象)適配器模式實(shí)現(xiàn)接口轉(zhuǎn)換77Adapter(適配器)模式應(yīng)用(對(duì)象)適配器模式實(shí)現(xiàn)接口轉(zhuǎn)77Adapter(適配器)模式理解1:接口轉(zhuǎn)換78客戶(鳥(niǎo))被適配者(鴨子)適配器請(qǐng)求轉(zhuǎn)換后的請(qǐng)求Adapter(適配器)模式理解1:接口轉(zhuǎn)換78客戶(鳥(niǎo))被78Adapter(適配器)模式79叫呷呷叫Adapter(適配器)模式79叫呷呷叫79Adapter(適配器)模式理解2:重新包裝,改變接口80Adapter(適配器)模式理解2:重新包裝,改變接口8080Adapter(適配器)模式類適配器81Adapter(適配器)模式類適配器8181Adapter(適配器)模式結(jié)構(gòu)對(duì)象Adapter82Adapter(適配器)模式結(jié)構(gòu)8282Adapter(適配器)模式結(jié)構(gòu)類Adapter83Adapter(適配器)模式結(jié)構(gòu)8383Adapter(適配器)模式意圖將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口Adapter模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作84Adapter(適配器)模式意圖8484Adapter(適配器)模式應(yīng)用舉例1我們打算編寫(xiě)一個(gè)畫(huà)圖軟件其中畫(huà)圓形已經(jīng)有了一個(gè)現(xiàn)成的類但是接口不同,不能直接使用85Adapter(適配器)模式應(yīng)用舉例18585Adapter(適配器)模式使用對(duì)象Adapter86Adapter(適配器)模式使用對(duì)象Adapter8686Adapter(適配器)模式應(yīng)用舉例2缺省適配模式——“魯達(dá)剃度”凡是和尚都應(yīng)該如此:87Adapter(適配器)模式應(yīng)用舉例28787Adapter(適配器)模式但是魯智深并不是這樣88魯智深::習(xí)武(){

拳打鎮(zhèn)關(guān)西();

大鬧五臺(tái)山();

倒拔垂楊柳();

火燒瓦官寺();}Adapter(適配器)模式但是魯智深并不是這樣88魯智深:88Adapter(適配器)模式所以當(dāng)初魯達(dá)剃度時(shí),眾僧說(shuō):“這個(gè)人形容丑惡,相貌兇頑,不可剃度”89?Adapter(適配器)模式所以當(dāng)初魯達(dá)剃度時(shí),眾僧說(shuō):8989Adapter(適配器)模式但是長(zhǎng)老卻說(shuō):“此人上應(yīng)天星,心地剛直。雖然時(shí)下兇頑,命中駁雜,久后卻得清靜。證過(guò)非凡,汝等皆不及他”90Adapter(適配器)模式但是長(zhǎng)老卻說(shuō):9090Adapter(適配器)模式“天星”就是缺省適配器當(dāng)你不想/不能實(shí)現(xiàn)接口的所有方法時(shí)利用缺省適配器類,提供這些方法的缺省實(shí)現(xiàn)從這個(gè)類再派生出的子類就可以不去實(shí)現(xiàn)那些不想實(shí)現(xiàn)的方法了91Adapter(適配器)模式“天星”就是缺省適配器9191真實(shí)世界中的適配器想一想Java語(yǔ)言中不同版本中有沒(méi)有需要進(jìn)行適配的92真實(shí)世界中的適配器想一想Java語(yǔ)言中不同版本中有沒(méi)有需要進(jìn)92真實(shí)世界中的適配器早期java版本中集合(Collection)類型(例如:Vector,Stack,Hashtable)都實(shí)現(xiàn)了一個(gè)elements()方法。該方法返回一個(gè)Enumeration(枚舉)新版本中開(kāi)始使用Iterator(迭代器)接口,這個(gè)接口和枚舉接口很像,但不同的是,迭代器還提供了刪除元素的能力。93真實(shí)世界中的適配器早期java版本中集合(Collectio93問(wèn)題面對(duì)遺留代碼,這些代碼會(huì)暴露出枚舉器接口,但我們又希望在新的代碼中只使用迭代器。解決辦法構(gòu)造一個(gè)適配器將枚舉適配到迭代器94問(wèn)題面對(duì)遺留代碼,這些代碼會(huì)暴露出枚舉器接口,但我們又希望在94959595969696publicclassEnumerationIteratorimplementsIterator{ //適配器看起來(lái)就是一個(gè)Iterator //我們使用組合的方式,將枚舉結(jié)合進(jìn)適配器中,用實(shí)例變量記錄

Enumerationenumeration; publicEnumerationIterator(Enumerationenumeration){ this.enumeration=enumeration; } //迭代器的hasNext其實(shí)是委托給enumeration的hasMoreElements方法

publicbooleanhasNext(){ returnenumeration.hasMoreElements(); } //迭代器的next其實(shí)是委托給enumeration的nextElement方法

publicObjectnext(){ returnenumeration.nextElement(); } //很不幸,我們不能支持迭代器的remove方法,所以必須放棄,這里是拋出一個(gè)異常

publicvoidremove(){ thrownewUnsupportedOperationException(); }}97publicclassEnumerationIterat97實(shí)例有一個(gè)類(adaptee)實(shí)現(xiàn)了數(shù)學(xué)中的冪次運(yùn)算,方法中需要傳入兩個(gè)參數(shù),一個(gè)是基數(shù)base,另外一個(gè)是冪次exp?,F(xiàn)在客戶端需要一個(gè)求得一個(gè)數(shù)的平方的函數(shù)接口(target),傳入一個(gè)數(shù),得到它的平方值。為了復(fù)用已經(jīng)存在的類adaptee,使用Adapter來(lái)適配adaptee,adapter實(shí)現(xiàn)了target接口。98實(shí)例有一個(gè)類(adaptee)實(shí)現(xiàn)了數(shù)學(xué)中的冪次運(yùn)算,方法中98999999在架構(gòu)層次上的應(yīng)用JDBC驅(qū)動(dòng)軟件與適配器模式JDBC給出一個(gè)客戶端通用的界面。每個(gè)數(shù)據(jù)庫(kù)引擎的JDBC驅(qū)動(dòng)軟件都是一個(gè)介于JDBC接口和數(shù)據(jù)庫(kù)引擎接口之間的適配器軟件抽象的JDBC接口和各個(gè)數(shù)據(jù)庫(kù)引擎的API之間都需要相應(yīng)的適配器軟件,即為各個(gè)數(shù)據(jù)庫(kù)引擎準(zhǔn)備的驅(qū)動(dòng)軟件。

100在架構(gòu)層次上的應(yīng)用JDBC驅(qū)動(dòng)軟件與適配器模式100100JDBC/ODBC橋梁如果沒(méi)有合適的JDBC驅(qū)動(dòng)軟件,用戶也可以通過(guò)ODBC驅(qū)動(dòng)軟件把JDBC通過(guò)一個(gè)JDBC/ODBC橋梁軟件與ODBC驅(qū)動(dòng)軟件連接起來(lái),從而達(dá)到連接數(shù)據(jù)庫(kù)的目的。101JDBC/ODBC橋梁101101設(shè)計(jì)原則:里氏代換原則例子1:“圓是不是橢圓?”在幾何學(xué)里,圓是橢圓的一種特殊情況因此,把橢圓看作父類,把圓作為子類102設(shè)計(jì)原則:里氏代換原則例子1:“圓是不是橢圓?”102102設(shè)計(jì)原則:里氏代換原則問(wèn)題橢圓有長(zhǎng)軸、短軸圓會(huì)完全繼承下來(lái)這些對(duì)于圓來(lái)說(shuō)毫無(wú)意義類似的:“正方形不是矩形”103Circlecircle;circle.GetMajorAxis();設(shè)計(jì)原則:里氏代換原則問(wèn)題103Circlecircle;103設(shè)計(jì)原則:里氏代換原則例子2:“企鵝不是鳥(niǎo)的子類”凡是鳥(niǎo)都會(huì)飛但是企鵝不會(huì)104設(shè)計(jì)原則:里氏代換原則例子2:“企鵝不是鳥(niǎo)的子類”104104設(shè)計(jì)原則:里氏代換原則例子3我們需要設(shè)計(jì)一個(gè)類FileName來(lái)描述文件名,而文件名不就是一個(gè)特殊的字符串么?所以我們?nèi)绱嗽O(shè)計(jì):105設(shè)計(jì)原則:里氏代換原則例子3105105設(shè)計(jì)原則:里氏代換原則問(wèn)題凡是字符串都支持相加操作,也就是說(shuō)兩個(gè)字符串相加,結(jié)果還是一個(gè)字符串可是兩個(gè)文件名相加,還是一個(gè)合法的文件名么?比如:“c:\a.txt”+“d:\b.txt”結(jié)果是:“c:\a.txtd:\b.txt”106設(shè)計(jì)原則:里氏代換原則問(wèn)題106106設(shè)計(jì)原則:里氏代換原則錯(cuò)在哪里?墨子論“取譬”“白馬,馬也;乘白馬,乘馬也。驪馬,馬也;乘驪馬,乘馬也?!苯忉專喊遵R、驪馬(黑馬)都是馬,既然馬可以騎,那么白馬和驪馬肯定也可以騎107設(shè)計(jì)原則:里氏代換原則錯(cuò)在哪里?107107設(shè)計(jì)原則:里氏代換原則LiskovSubstitutionPrinciple一個(gè)軟件如果使用的是一個(gè)父類的話,如果把該父類換成子類,它不能察覺(jué)出父類對(duì)象和子類對(duì)象的區(qū)別也就是凡是父類適用的地方子類也適用繼承只有滿足里氏代換原則才是合理的108設(shè)計(jì)原則4:里氏代換原則凡是父類適用的地方子類應(yīng)當(dāng)也適用設(shè)計(jì)原則:里氏代換原則LiskovSubstitution108設(shè)計(jì)原則:里氏代換原則反過(guò)來(lái)的代換不成立子類適用的地方不要求父類一定能適用墨子又說(shuō)“娣,美人也,愛(ài)娣,非愛(ài)美人也......盜,人也,惡盜,非惡人也”妹妹是美女,哥哥喜歡妹妹,并不是因?yàn)橄矚g美女小偷是人,討厭小偷,并不討厭所有人109設(shè)計(jì)原則:里氏代換原則反過(guò)來(lái)的代換不成立109109設(shè)計(jì)原則:里氏代換原則Java語(yǔ)言對(duì)此類問(wèn)題的防范它的String類是final的,不能繼承正確的方法使用Adapter模式110設(shè)計(jì)原則:里氏代換原則Java語(yǔ)言對(duì)此類問(wèn)題的防范110110設(shè)計(jì)原則:里氏代換原則Java中的反例它的Stack類是從Vector類繼承下來(lái)的“棧不就是施加了訪問(wèn)限制的數(shù)組么?”所以“StackIs-AVector”111設(shè)計(jì)原則:里氏代換原則Java中的反例111111設(shè)計(jì)原則:里氏代換原則用里氏代換原則來(lái)判斷凡是數(shù)組行得通的地方,換成棧也行得通么?Vector可以隨機(jī)訪問(wèn),可以任意修改里面的元素...這些都是Stack所不允許的因此Stack不能從Vector繼承下來(lái),它不能擁有Vector的接口112設(shè)計(jì)原則:里氏代換原則用里氏代換原則來(lái)判斷112112設(shè)計(jì)原則:里氏代換原則看看C++STL是怎么辦的STL中的stack其實(shí)是一個(gè)Adapter113template<classT,classCont=deque<T>>classstack{public:

void

push(constvalue_type&x){c.push_back(x);}

void

pop(){c.pop_back(x);}protected:Contc;};設(shè)計(jì)原則:里氏代換原則看看C++STL是怎么辦的113te113設(shè)計(jì)模式-工廠模式設(shè)計(jì)模式-工廠模式當(dāng)看到“new”,就會(huì)想到“具體”115當(dāng)看到“new”,就會(huì)想到“具體”115115116一個(gè)計(jì)算器例子publicclassOperation{ privatedoublenumberA=0; privatedoublenumberB=0; publicvirtualdoubleGetResult(){ doubleresult=0; returnresult; }}classOperationAdd:Operation{ publicoverridedoubleGetResult(){ doubleresult=0; result=numberA+numberB; returnresult;}116一個(gè)計(jì)算器例子publicclassOperati116當(dāng)遇到一群相關(guān)的具體類時(shí),通常見(jiàn)到下面的代碼OperationcreateOperation(Stringoperate){

Operationoper;

switch(operate){case”+”:oper=newOperationAdd();break;case”=”:oper=newOperationSub();break;case”*”:oper=newOperationMul();break;……..}}117當(dāng)遇到一群相關(guān)的具體類時(shí),通常見(jiàn)到下面的代碼117117如果計(jì)算器要增加更多的運(yùn)算類型怎么辦?118如果計(jì)算器要增加更多的運(yùn)算類型怎么辦?118118簡(jiǎn)單工廠開(kāi)始封裝創(chuàng)建對(duì)象的代碼建立一個(gè)簡(jiǎn)單工廠當(dāng)需要Operation時(shí),就叫工廠做一個(gè)119簡(jiǎn)單工廠開(kāi)始封裝創(chuàng)建對(duì)象的代碼119119定義簡(jiǎn)單工廠120定義簡(jiǎn)單工廠120120PublicclassOperationFactory{ publicstaticOperationcreateOperate(Stringoperate){ Operationoper=null; switch(operate){case”+”:oper=newOperationAdd();break;case”=”:oper=newOperationSub();break;case”*”:oper=newOperationMul();break;case”/”:oper=newOperationDiv();break;}returnoper;}}121簡(jiǎn)單工廠實(shí)現(xiàn)PublicclassOperationFactory{121客戶端的實(shí)現(xiàn)

Operationoper;oper=OperationFactory.createOperate(“+”);oper.NumberA=1;oper.NumberB=2;doubleresult=oper.GetResult();122客戶端的實(shí)現(xiàn)122122簡(jiǎn)單工廠模式的優(yōu)點(diǎn)123簡(jiǎn)單工廠類中包含了必要的邏輯判斷,根據(jù)客戶端的選擇條件動(dòng)態(tài)實(shí)例化相關(guān)的類,對(duì)于客戶端來(lái)說(shuō),去除了與具體產(chǎn)品的依賴。就像計(jì)算器,讓客戶端不用管該用哪個(gè)類的實(shí)例,只要把‘+’給工廠,工廠自動(dòng)就給出了實(shí)例,客戶端只要去做運(yùn)算就可以了,不同的實(shí)例會(huì)實(shí)現(xiàn)不同的運(yùn)算。簡(jiǎn)單工廠實(shí)現(xiàn)了責(zé)任的分割。簡(jiǎn)單工廠模式的優(yōu)點(diǎn)123簡(jiǎn)單工廠類中包含了必要的邏輯判斷,根123問(wèn)題如果要加一個(gè)“求M數(shù)的N此方”的功能,就要在原有方法中加一個(gè)分支條件,就要修改原有的類,違背了開(kāi)放-封閉原則,于是工廠方法就來(lái)了。124問(wèn)題如果要加一個(gè)“求M數(shù)的N此方”的功能,就要在原有方法中加124定義工廠方法模式工廠方法模式定義了一個(gè)創(chuàng)建對(duì)象的接口由子類決定實(shí)例化的類是哪一個(gè)工廠方法使一個(gè)類的實(shí)例化延遲到其子類。125定義工廠方法模式工廠方法模式定義了一個(gè)創(chuàng)建對(duì)象的接口125125遵循倒置依賴原則的指導(dǎo)方針變量不可以持有具體類的引用如果使用new,就會(huì)持有具體類的引用可以改用工廠來(lái)避開(kāi)這樣的做法不要讓類派生自具體類如果派生自具體類,就會(huì)依賴具體類請(qǐng)派生自一個(gè)抽象(接口或抽象類)不是隨時(shí)都要遵循這個(gè)原則如直接實(shí)例化字符串對(duì)象126遵循倒置依賴原則的指導(dǎo)方針變量不可以持有具體類的引用126126應(yīng)用依賴倒置原則要依賴抽象,不要依賴具體類我們把工廠類抽象出一個(gè)接口,這個(gè)接口只有一個(gè)方法,就是創(chuàng)建抽象產(chǎn)品的工廠方法。然后,所有的要生產(chǎn)具體類的工廠,就去實(shí)現(xiàn)這個(gè)接口。這樣,一個(gè)簡(jiǎn)單工廠模式的工廠類,就變成了一個(gè)工廠抽象接口和多個(gè)具體生產(chǎn)對(duì)象的工廠。于是,我們要增加‘求M數(shù)的N次方’的功能時(shí),就不需要更改原有的工廠類了,只需要增加此功能的運(yùn)算類和相應(yīng)的工廠類就可以了。127應(yīng)用依賴倒置原則要依賴抽象,不要依賴具體類127127工廠方法模式實(shí)現(xiàn)128工廠方法模式實(shí)現(xiàn)128128工廠方法模式實(shí)現(xiàn)先構(gòu)建一個(gè)工廠接口InterfaceIFactory{OperationCreateOperation();}129工廠方法模式實(shí)現(xiàn)先構(gòu)建一個(gè)工廠接口129129然后加減乘除各建一個(gè)具體工廠去實(shí)現(xiàn)這個(gè)接口classAddFactory:IFactory{publicOperationCreateOperation(){returnnewOperationAdd();}}classSubFactory:IFactory{publicOperationCreateOperation(){ returnnewOperationSub();}}130工廠方法模式實(shí)現(xiàn)然后加減乘除各建一個(gè)具體工廠去實(shí)現(xiàn)這個(gè)接口130工廠方法模式130然后加減乘除各建一個(gè)具體工廠去實(shí)現(xiàn)這個(gè)接口classMulFactory:IFactory{publicOperationCreateOperation(){returnnewOperationMul();}}classDivFactory:IFactory{publicOperationCreateOperation(){returnnewOperationDiv();}}131工廠方法模式實(shí)現(xiàn)然后加減乘除各建一個(gè)具體工廠去實(shí)現(xiàn)這個(gè)接口131工廠方法模式131客戶端的實(shí)現(xiàn)

IFactoryoperFactory=newAddFactory();Operationoper=operFactory.CreateOperation();oper.NumberA=1;oper.NumberB=2;doubleresult=oper.GetResult();132工廠方法模式實(shí)現(xiàn)客戶端的實(shí)現(xiàn)132工廠方法模式實(shí)現(xiàn)132工廠方法模式實(shí)現(xiàn)時(shí),客戶端需要決定實(shí)例化哪一個(gè)工廠來(lái)實(shí)現(xiàn)運(yùn)算類,選擇判斷的問(wèn)題還是存在的,也就是說(shuō),工廠方法把簡(jiǎn)單工廠的內(nèi)部邏輯判斷轉(zhuǎn)移到了客戶端代碼來(lái)進(jìn)行。如果要加功能,本來(lái)是改工廠類的,而現(xiàn)在是修改客戶端。133工廠方法模式工廠方法模式實(shí)現(xiàn)時(shí),客戶端需要決定實(shí)例化哪一個(gè)工廠來(lái)實(shí)現(xiàn)運(yùn)算133

一個(gè)抽象產(chǎn)品類,可以派生出多個(gè)具體產(chǎn)品類。

一個(gè)抽象工廠類,可以派生出多個(gè)具體工廠類。

每個(gè)具體工廠類只能創(chuàng)建一個(gè)具體產(chǎn)品類的實(shí)例。134工廠方法模式 一個(gè)抽象產(chǎn)品類,可以派生出多個(gè)具體產(chǎn)品類。

一個(gè)抽象134雷鋒工廠雷鋒是眾人皆知的做好人好事的模范。作為一名大學(xué)生,每個(gè)人都可以以雷鋒做好事的名義去幫助老人。在這里,’雷鋒’類,擁有掃地、洗衣、買(mǎi)米等方法?!畬W(xué)雷鋒的大學(xué)生’類是‘雷鋒’類的一個(gè)繼承。而大學(xué)生是要畢業(yè)的,幫助老人是長(zhǎng)期的,所以‘社區(qū)志愿者’更適合。于是,增加一個(gè)繼承‘雷鋒’類的‘社區(qū)志愿者’類。135雷鋒工廠雷鋒是眾人皆知的做好人好事的模范。135135雷鋒類classLeiFeng{ publicvoidSweep(){ Console.WriteLine(“掃地”); } publicvoidWash(){ Console.WriteLine(“洗衣”); } publicvoidBuyRice(){ Console.WriteLine(“買(mǎi)米”); }}136雷鋒類classLeiFeng{136136大學(xué)生類及社區(qū)志愿者classUndergraduate:LeiFeng{}classVolunteer:LeiFeng{}137大學(xué)生類及社區(qū)志愿者classUndergraduate137簡(jiǎn)單工廠模式ClassSimpleFactory{publicstaticLeiFengCreateLeiFeng(stringtyple){LeiFengresult=null;switch(type){case”學(xué)雷鋒的大學(xué)生”:result=newUndergradute();break;case”社區(qū)志愿者”:result=newVolunteer();break;}returnresult;}}138簡(jiǎn)單工廠模式ClassSimpleFactory{138138客戶端的實(shí)現(xiàn)LeiFengstudentA=SimpleFacatory.CreateLeiFeng(“學(xué)雷鋒的大學(xué)生”);studentA.BuyRice();LeiFengstudentB=SimpleFacatory.CreateLeiFeng(“學(xué)雷鋒的大學(xué)生”);studentB.Sweep();LeiFengstudentC=SimpleFacatory.CreateLeiFeng(“學(xué)雷鋒的大學(xué)生”);studentC.Wash();139簡(jiǎn)單工廠模式客戶端的實(shí)現(xiàn)139簡(jiǎn)單工廠模式139在這里,需要再任何實(shí)例化的時(shí)候?qū)懗鲞@個(gè)工廠的代碼。這里有重復(fù),于是用工廠方法模式來(lái)寫(xiě)。140在這里,需要再任何實(shí)例化的時(shí)候?qū)懗鲞@個(gè)工廠的代碼。這里有重復(fù)140工廠方法模式InterfaceIFactory{LeiFengCreateLeiFeng();}classUndergraduteFactory:IFactory{publicLeiFengCreateLeiFeng(){returnnewUndergraduate();}}141工廠方法模式InterfaceIFactory141141classVolunteerFactory:IFactory{publicLeiFengCreateLeiFeng(){returnnewVolunteer();}}客戶端代碼

Ifactoryfactory=newUndergraduateFactory(); LeiFengstudentA=factory.CreateLeiFeng(); LeiFengstudentB=factory.CreateLeiFeng(); LeiFengstudentC=factory.CreateLeiFeng();studentA.BuyRice();studentB.Sweep();studentC.Wash();142工廠方法模式classVolunteerFactory:IFacto142在這里,盡管如果要換成‘社區(qū)志愿者’也還是要修改代碼,但只用修改一處就可以。工廠方法克服了簡(jiǎn)單工廠違背開(kāi)放-封閉原則的缺點(diǎn),又保持了封裝對(duì)象創(chuàng)建過(guò)程的優(yōu)點(diǎn)。它們都是集中封裝了對(duì)象的創(chuàng)建,使得要更換對(duì)象時(shí),不需要做大的改動(dòng)就可實(shí)現(xiàn),降低了客戶程序與產(chǎn)品對(duì)象的耦合。143工廠方法模式在這里,盡管如果要換成‘社區(qū)志愿者’也還是要修改代碼,但只用143工廠方法模式是簡(jiǎn)單工廠模式的進(jìn)一步抽象和推廣,由于使用了多態(tài)性,工廠方法模式保持了簡(jiǎn)單工廠模式的優(yōu)點(diǎn),而且克服了它的缺點(diǎn)。但缺點(diǎn)是由于每加一個(gè)產(chǎn)品,就需要加一個(gè)產(chǎn)品工廠的類,增加了額外了開(kāi)發(fā)量。144工廠方法模式工廠方法模式是簡(jiǎn)單工廠模式的進(jìn)一步抽象和推廣,由于使用了多態(tài)144抽象工廠模式提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而無(wú)需指定它們具體的類。145抽象工廠模式提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而無(wú)145定義抽象工廠模式146定義抽象工廠模式146146數(shù)據(jù)訪問(wèn)程序用戶類User,假設(shè)只有ID和Name兩個(gè)字段。SqlserverUser類和AccessUser類,用于操作User表,假設(shè)只有“新增用戶”和“得到用戶”方法。SqlserverUser類,用于訪問(wèn)SQLServer的用戶。AccessUser類,用于訪問(wèn)Access的用戶。147數(shù)據(jù)訪問(wèn)程序用戶類User,假設(shè)只有ID和Name兩個(gè)字段。147用工廠方法模式的數(shù)據(jù)訪問(wèn)程序148用工廠方法模式的數(shù)據(jù)訪問(wèn)程序148148InterfaceIUser{voidInsert(Useruser);UserGetUser(intid);}classSqlserverUser:IUser{

publicvoidInsert(Useruser){Console.WriteLine(“在SQLServer中給User表增加一條記錄”);}publicvoidGetUser(intid){Console.WriteLine(“在SQLServer中根據(jù)ID得到User表的一條記錄”);returnnull;}}149用工廠方法模式的數(shù)據(jù)訪問(wèn)程序InterfaceIUser149用工廠方法模式的數(shù)據(jù)訪問(wèn)149classAccessUser:IUser{

publicvoidInsert(Useruser){Console.WriteLine(“在Access中給User表增加一條記錄”);}publicvoidGetUser(intid){Console.WriteLine(“在Access中根據(jù)ID得到User表的一條記錄”);returnnull;}}150classAccessUser:IUser150150工廠方法IFactory接口:定義一個(gè)創(chuàng)建訪問(wèn)User表對(duì)象的抽象的工廠接口。InterfaceIFactory{IuserCreateUser();}151工廠方法151151SqlServerFactory類,AccessFactory類實(shí)現(xiàn)接口classSqlServerFactory:IFactory{publicIuserCreateUser(){returnnewSqlserverUser();}}classAccessFactory:IFactory{publicIuserCreateUser(){returnnewAccessUser();}}152SqlServerFactory類,AccessFacto152客戶端實(shí)現(xiàn)StaticvoidMain(string[]args){Useruser=newUser();Ifactoryfactory=newSqlServerFactory();Iuseriu=factory.CreateUser();iu.Insert(user);iu.GetUser(1);Console.Read();}153客戶端實(shí)現(xiàn)StaticvoidMain(string[]153用抽象工廠模式的數(shù)據(jù)訪問(wèn)程序154用抽象工廠模式的數(shù)據(jù)訪問(wèn)程序154154Idepartment接口,用于客戶端訪問(wèn),解除與具體數(shù)據(jù)庫(kù)訪問(wèn)的耦合。interfaceIDepartment{voidInsert(Departmentdepartment);DepartmentGetDepartment(intid);}SqlserverDepartment類,AccessDepartment類分別用于訪問(wèn)SQLSever、Access的Department。155Idepartment接口,用于客戶端訪問(wèn),解除與具體數(shù)據(jù)庫(kù)155classSqlserverDepartment:IDepartment{publicvoidInsert(Departmentdepartment){Console.WriteLine(“在SQLServer中的Department表

增加一條記錄”);}publicDepartmentGetDepartment(intid){Console.WriteLine(“在SQLServer中根據(jù)ID得到 Department表中的一條記錄”);returnnull;}}156classSqlserverDepartment:ID156classAccessDepartment:IDepartment{publicvoidInsert(Departmentdepartment){Console.WriteLine(“在Access中的Department表增加

一條記錄”);}publicDepartmentGetDepartment(intid){Console.WriteLine(“在Access中根據(jù)ID得到 Department表中的一條記錄”);returnnull;}}157classAccessDepartment:IDepa157interfaceIFactory{IuserCreateUser();IDepartmentCreateDepartment();}classSqlServerFactory:IFactory{publicIuserCreateUser(){returnnewSqlserverUser();}publicIDepartmentCreateDepartment(){returnnewSqlServerDepartment();}}158interfaceIFactory158158classAccessFactory:IFactory{publicIuserCreateUser(){returnnewAccessUser();}publicIDepartmentCreateDepartment(){returnnewAccessDepartment();}}159classAccessFactory:IFactory159客戶端實(shí)現(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客戶端實(shí)現(xiàn):160160抽象工廠模式的優(yōu)點(diǎn)易于交換產(chǎn)品系列,由于具體工廠類在一個(gè)應(yīng)用中只需要在初始化時(shí)出現(xiàn)一次,這就使得改變一個(gè)應(yīng)用的具體工廠變得非常容易,它只需要改變具體工廠即可使用不同的產(chǎn)品配置。它讓具體的創(chuàng)建實(shí)例過(guò)程與客戶端分離,客戶端是通過(guò)它們的抽象接口操縱實(shí)例,產(chǎn)品的具體類名也被具體工廠的實(shí)現(xiàn)分離,不會(huì)出現(xiàn)在客戶代碼中。161抽象工廠模式的優(yōu)點(diǎn)易于交換產(chǎn)品系列,由于具體工廠類在一個(gè)應(yīng)用161抽象工廠模式

多個(gè)抽象產(chǎn)品類,每個(gè)抽象產(chǎn)品類可以派生出多個(gè)具體產(chǎn)品類。

一個(gè)抽象工廠類,可以派生出多個(gè)具體工廠類。

每個(gè)具體工廠類可以創(chuàng)建多個(gè)具體產(chǎn)品類的實(shí)例。

162抽象工廠模式 多個(gè)抽象產(chǎn)品類,每個(gè)抽象產(chǎn)品類可以派生出多個(gè)具162比較工廠方法和抽象方法抽象工廠的需求:創(chuàng)建一個(gè)產(chǎn)品家族負(fù)責(zé)在抽象工廠中創(chuàng)建產(chǎn)品的方法,通常是以“工廠方法”來(lái)實(shí)現(xiàn)的163比較工廠方法和抽象方法抽象工廠的需求:創(chuàng)建一個(gè)產(chǎn)品家族163163FactoryMethod(工廠方法)模式例子:“去快餐廳吃飯”164FactoryMethod(工廠方法)模式例子:“去快餐廳164165void

BuyFood(string

餐館,string食品){

if(餐館=="KFC"){

if(食品=="Chicken")hamburger=newKFCChickenHamburger;

else

if(food=="Fish")hamburger=newKFCFishHamburger;}

else

if(restaurant=="McDonald"){

if(food=="Chicken")hamburger=newMcDonaldChickenHamburger;

else

if(food=="Fish")hamburger=newMcDonaldFishHamburger;}}165voidBuyFood(string餐館,st165FactoryMethod(工廠方法)模式增加一種新的食物呢?166FactoryMethod(工廠方法)模式增加一種新的食物166FactoryMethod(工廠方法)模式傳統(tǒng)設(shè)計(jì)的缺點(diǎn)依賴具體167void

BuyFood(string

餐館,string食品){

if(餐館=="KFC"){

if(食品=="Chicken")hamburger=new

KFCChickenHamburger;

else

if(food=="Fish")hamburger=new

KFCFishHamburger;}...FactoryMethod(工廠方法)模式傳統(tǒng)設(shè)計(jì)的缺點(diǎn)1167FactoryMethod(工廠方法)模式“Abstractionshouldnotdependupondetails.Detailsshoulddependuponabstractions”168設(shè)計(jì)原則5:依賴倒置原則抽象不應(yīng)當(dāng)依賴于細(xì)節(jié)細(xì)節(jié)應(yīng)當(dāng)依賴于抽象FactoryMethod(工廠方法)模式168設(shè)計(jì)原則5168設(shè)計(jì)原則:依賴倒置原則為什么說(shuō)“倒置”傳統(tǒng)的設(shè)計(jì)是抽象層依賴具體層傳統(tǒng)的重用,側(cè)重于具體層次的模塊,比如算法、數(shù)據(jù)結(jié)構(gòu)、函數(shù)庫(kù)因此軟件的高層模塊依賴低層模塊169傳統(tǒng)的依賴方向設(shè)計(jì)原則:依賴倒置原則為什么說(shuō)“倒置”169傳169設(shè)計(jì)原則:依賴倒置原則高層依賴低層的問(wèn)題抽象層包含的是系統(tǒng)的業(yè)務(wù)邏輯和宏觀的、戰(zhàn)略性的決定,是必然性的體現(xiàn)具體層則含有與實(shí)現(xiàn)相關(guān)的算法和邏輯,以及戰(zhàn)術(shù)性的決定,帶有相當(dāng)大的偶然性選擇。具體層經(jīng)常有變動(dòng),難免出現(xiàn)錯(cuò)誤必然依賴偶然,穩(wěn)定依賴變動(dòng)?170設(shè)計(jì)原則:依賴倒置原則高層依賴低層的問(wèn)題170170設(shè)計(jì)原則:依賴倒置原則依賴具體的缺點(diǎn)171設(shè)計(jì)原則:依賴倒置原則依賴具體的缺點(diǎn)171171設(shè)計(jì)原則:依賴倒置原則依賴抽象抽象一般不會(huì)變動(dòng)這樣代碼不會(huì)受易變的具體層影響172設(shè)計(jì)原則:依賴倒置原則依賴抽象172172設(shè)計(jì)原則:針對(duì)接口編程如何做到“依賴倒置”?“Programtoaninterface,notanimplementation”173設(shè)計(jì)原則6:針對(duì)接口編程要針對(duì)接口編程不要針對(duì)實(shí)現(xiàn)編程設(shè)計(jì)原則:針對(duì)接口編程如何做到“依賴倒置”?173設(shè)計(jì)原則6173設(shè)計(jì)原則:針對(duì)接口編程“針對(duì)接口編程”的一些建議變量、參數(shù)、返回值等應(yīng)聲明為抽象類不要繼承非抽象類不要重載父類的非抽象方法當(dāng)然這些只是建議實(shí)際情況要權(quán)衡利弊174設(shè)計(jì)原則:針對(duì)接口編程“針對(duì)接口編程”的一些建議174174FactoryMethod(工廠方法)模式“女?huà)z摶土造人”《風(fēng)俗通》:“俗說(shuō)天開(kāi)地辟,未有人民。女?huà)z摶黃土為人?!?75FactoryMethod(工廠方法)模式“女?huà)z摶土造人”175FactoryMethod(工廠方法)模式簡(jiǎn)單工廠:根據(jù)傳入的參數(shù),決定創(chuàng)建哪一個(gè)產(chǎn)品類對(duì)象176Human*

NvWa::CreateHuman(stringname){

if(name

==“ZhangSan") returnnew

ZhangSan;

elseif(name

==“LiSi") returnnew

LiSi;

elseif(name==“WangErMaZi") returnnew

WangErMaZi;}FactoryMethod(工廠方法)模式簡(jiǎn)單工廠:根據(jù)傳176FactoryMethod(工廠方法)模式簡(jiǎn)單工廠的優(yōu)缺點(diǎn)優(yōu)點(diǎn):實(shí)現(xiàn)了責(zé)任分割利用判斷邏輯,決定實(shí)例化哪一個(gè)產(chǎn)品類客戶端可以免除直接創(chuàng)建產(chǎn)品類對(duì)象的責(zé)任,僅僅使用該產(chǎn)品缺點(diǎn):沒(méi)有完全做到“開(kāi)-閉”一旦增加新的產(chǎn)品,需要修改工廠的代碼但是客戶代碼不需要修改“我不入地獄誰(shuí)入地獄”177FactoryMethod(工廠方法)模式簡(jiǎn)單工廠的優(yōu)缺點(diǎn)177FactoryMethod(工廠方法)模式“女?huà)z舉繩造人”“女?huà)z摶土為人,劇務(wù),力不暇供,乃引繩于桓泥中,舉以為人?!?78FactoryMethod(工廠方法)模式“女?huà)z舉繩造人”178FactoryMethod(工廠方法)模式簡(jiǎn)單工廠的問(wèn)題所有具體產(chǎn)品對(duì)象的創(chuàng)建都放在一個(gè)類中,一旦增加新的產(chǎn)品,當(dāng)然工廠類要被修改工廠方法:使用多態(tài)來(lái)應(yīng)對(duì)提供一個(gè)抽象工廠的接口具體工廠分別負(fù)責(zé)創(chuàng)建具體產(chǎn)品對(duì)象增加新的產(chǎn)品只需要相應(yīng)增加新的具體工廠類179FactoryMethod(工廠方法)模式簡(jiǎn)單工廠的問(wèn)題1179FactoryMethod(工廠方法)模式意圖定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類決定實(shí)例化哪一個(gè)類使一個(gè)類的實(shí)例化延遲到其子類優(yōu)點(diǎn)封裝了創(chuàng)建具體對(duì)象的工作使得客戶代碼“針對(duì)接口編程”,保持對(duì)變化的“關(guān)閉”180FactoryMethod(工廠方法)模式意圖180180FactoryM

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(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)論