課件-面向?qū)ο骳設(shè)計(jì)原則_第1頁(yè)
課件-面向?qū)ο骳設(shè)計(jì)原則_第2頁(yè)
課件-面向?qū)ο骳設(shè)計(jì)原則_第3頁(yè)
課件-面向?qū)ο骳設(shè)計(jì)原則_第4頁(yè)
課件-面向?qū)ο骳設(shè)計(jì)原則_第5頁(yè)
已閱讀5頁(yè),還剩83頁(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)介

1/17/20231提高面向?qū)ο笤O(shè)計(jì)復(fù)用性的設(shè)計(jì)原則面向?qū)ο蟮脑O(shè)計(jì)原則1/17/20232設(shè)計(jì)目標(biāo)可擴(kuò)展性(Extensibility):新功能易加入系統(tǒng)。靈活性(Flexibility):允許代碼修改平穩(wěn)發(fā)生,不會(huì)涉及很多其他模塊??刹迦胄?Pluggability):容易將一個(gè)類換為另一個(gè)具有同樣接口的類。1/17/20233軟件復(fù)用重要性較高的生產(chǎn)率較高的軟件質(zhì)量恰當(dāng)使用復(fù)用,可改善系統(tǒng)的可維護(hù)性1/17/20234使一個(gè)系統(tǒng)可在更高的層次上提供了可復(fù)用性抽象化和繼承:使概念和定義可復(fù)用多態(tài):使實(shí)現(xiàn)和應(yīng)用可復(fù)用抽象化和封裝:可保持和促進(jìn)系統(tǒng)的可維護(hù)性面向?qū)ο笤O(shè)計(jì)1/17/20235抽象層次是一個(gè)應(yīng)用系統(tǒng)作戰(zhàn)略性判斷和決定的地方,那么抽象層次就應(yīng)當(dāng)是較為穩(wěn)定的,應(yīng)當(dāng)是復(fù)用的重點(diǎn)。復(fù)用的焦點(diǎn)不再集中在函數(shù)和算法等具體實(shí)現(xiàn)細(xì)節(jié)上,而是集中在最重要的含有宏觀商業(yè)邏輯的抽象層次上。既然如果抽象層次的模塊相對(duì)獨(dú)立于具體層次的模塊的話,那么具體層次內(nèi)部的變化就不會(huì)影響到抽象層次的結(jié)構(gòu),所以抽象層次的復(fù)用就會(huì)較為容易。復(fù)用1/17/20236面向?qū)ο笤O(shè)計(jì)中,可維護(hù)性復(fù)用是以設(shè)計(jì)原則和設(shè)計(jì)模式為基礎(chǔ)的。面向?qū)ο髲?fù)用1/17/202371.開閉原則OCP:Open-ClosedPrinciple2. 里氏替換原則LSP:LiskovSubstitutionPrinciple3. 依賴倒轉(zhuǎn)原則DIP:DependencyInversionPrinciple4. 接口隔離原則ISP:InterfaceSegregationPrinciple5. 組合復(fù)用原則positoinResusePrinciple6. 迪米特法則LoD:LawofDemeter7.單一職責(zé)原則(SRP)面向?qū)ο笤O(shè)計(jì)原則1/17/20238軟件組成實(shí)體應(yīng)該是對(duì)擴(kuò)展開放的,但是對(duì)修改是關(guān)閉的。(SoftwareEntitiesShouldBeOpenForExtension,ButClosedForModification)1988年,勃蘭特·梅耶(BertrandMeyer)在他的著作《面向?qū)ο筌浖?gòu)造(ObjectOrientedSoftwareConstruction)》中提出1.開-閉原則OCP1/17/20239這句話說(shuō)得略微有點(diǎn)專業(yè),我們把它講得更通俗一點(diǎn),也就是:軟件系統(tǒng)中包含的各種組件,例如模塊(Modules)、類(Classes)以及函數(shù)(Functions)等等,應(yīng)該在不修改現(xiàn)有代碼的基礎(chǔ)上,引入新功能?!伴_”,是允許對(duì)其進(jìn)行功能擴(kuò)展的;“閉”,是指對(duì)于原有代碼的修改是封閉的,即不應(yīng)該修改原有的代碼。1/17/202310在設(shè)計(jì)一個(gè)軟件的時(shí)候,應(yīng)當(dāng)使這個(gè)軟件可以在不被修改的前提下擴(kuò)展已有模塊,尤其是最重要的抽象層模塊不能動(dòng):保證穩(wěn)定性和延續(xù)性可以擴(kuò)展新模塊:增加新行為,保證靈活性1/17/202311開-閉法則認(rèn)為應(yīng)該試圖去設(shè)計(jì)出永遠(yuǎn)也不需要改變的模塊。關(guān)鍵在于抽象化:可給系統(tǒng)定義一個(gè)一勞永逸,不再更改的抽象設(shè)計(jì),此設(shè)計(jì)允許有無(wú)窮無(wú)盡的行為在實(shí)現(xiàn)層被實(shí)現(xiàn)。抽象層可以允許、支持所有擴(kuò)展。PC外設(shè)開-閉原則1/17/202312優(yōu)點(diǎn)可復(fù)用性好:提高適應(yīng)性、靈活性我們可以在軟件完成以后,仍然可以對(duì)軟件進(jìn)行擴(kuò)展,加入新的功能,非常靈活。因此,這個(gè)軟件系統(tǒng)就可以通過(guò)不斷地增加新的組件,來(lái)滿足不斷變化的需求。可維護(hù)性好:由于對(duì)于已有的軟件系統(tǒng)的組件,特別是它的抽象底層不去修改,因此,我們不用擔(dān)心軟件系統(tǒng)中原有組件的穩(wěn)定性,這就使變化中的軟件系統(tǒng)有一定的穩(wěn)定性和延續(xù)性。1/17/202313玉帝遵照“開-閉”原則維護(hù)天庭秩序當(dāng)年孫悟空大鬧天空,向天庭發(fā)出挑戰(zhàn):“皇帝輪流做,明年到我家......只教他搬出去,將天宮讓與我!”太白金星給玉皇大帝 建議道:“降一道招安 圣旨,把他宣來(lái)上界...

與他籍名在箓...

一則不動(dòng)眾勞師, 二則收仙有道也。”1/17/202314“封裝可變性原則”gof:“考慮你的設(shè)計(jì)中什么可能會(huì)發(fā)生變化......考慮你允許什么發(fā)生變化而不讓這一變化導(dǎo)致重新設(shè)計(jì)”Shalloway:“發(fā)現(xiàn)變化點(diǎn),并封裝之”一種可變性不應(yīng)散落在代碼的很多角落一種可變性不應(yīng)當(dāng)與另一種可變性混合在一起1/17/202315一個(gè)軟件系統(tǒng)的所有模塊不可能都滿足OCP,但是應(yīng)該努力最小化這些不滿足OCP的模塊數(shù)量。開-閉原則1/17/202316PublicclassPart{privatedoublebasePrice;publicvoidsetPrice(doubleprice){basePrice=price;}publicdoublegetPrice(){returnbasePrice;}}OCP例-類1/17/202317Publicdoubletotalprice(Part[]parts){doubletotal=0.0;for(inti=0;i<parts.length;i++){total+=parts[i].getPrice();}returntotal;}OCP例-某類方法1/17/202318內(nèi)存折扣?思考1/17/202319Publicdoubletotalprice(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;}方法1/17/202320符合OCP嗎?思考1/17/202321PublicclassMemoryextendsPart{publicdoublegetPrice(){returnbasePrice*0.9;}}方法?1/17/202322采用一個(gè)PricePolicy類,通過(guò)對(duì)其進(jìn)行繼承以提供不同的計(jì)價(jià)策略更好的方法?1/17/202323PublicclassPart{privatePricePolicypricePolicy;publicvoidsetPricePolicy(PricePolicypolicy){pricePolicy=policy;}publicvoidsetPrice(doubleprice){pricePolicy.setPrice(price);}publicdoublegetPrice(){returnpricePolicy.getPrice();}}方法1/17/202324PublicclassPricePolicy{privatedoublebasePrice;publicvoidsetPrice(doubleprice){basePrice=price;}publicdoublegetPrice(){returnbasePrice;}}價(jià)格策略1/17/202325PublicclassSaleextendsPricePolicy{privatedoublediscount;publicvoidsetDiscount(doublediscount){this.discount=discount;}publicdoublegetPrice(){returnbasePrice*discount;}}銷售策略1/17/202326符合OCP了嗎?思考1/17/202327應(yīng)用實(shí)例我們有一個(gè)需要在標(biāo)準(zhǔn)的GUI上繪制園和正方形的應(yīng)用程序。圓和正方形必須要按照特定的順序繪制。我們將創(chuàng)建一個(gè)列表,列表由按照適當(dāng)?shù)捻樞蚺帕械膱@和正方形組成,程序遍歷該列表,一次繪制出每個(gè)圓和正方形。1/17/202328先考慮違反OCP的過(guò)程化方法定義一個(gè)DrawAllShapes函數(shù)使用SWITCH來(lái)分支繪制圖形為什么不符合OCP?因?yàn)樗鼘?duì)于新的形狀類型的添加不是封閉的每增加一種新的形狀類型,都必須要更改這個(gè)函數(shù)1/17/202329這樣的設(shè)計(jì)糟糕在哪里?增加形狀會(huì)導(dǎo)致所有的程序、變量重新編譯和部署想在另一個(gè)程序中復(fù)用DrawAllShape這個(gè)函數(shù)時(shí),都必須要附帶上Square和Circle,即時(shí)那個(gè)程序不需要它們。1/17/202330怎樣遵循OCP編寫一個(gè)shape抽象類這個(gè)類僅有一個(gè)抽象方法draw()所有形狀都從這個(gè)類派生當(dāng)繪制一種新的形狀,只需要增加一個(gè)新的shape類的派生類。而DrawAllShapes函數(shù)并不需要改變。1/17/202331使用指向基類(超類)的引用的函數(shù),必須能夠在不知道具體派生類(子類)對(duì)象類型的情況下使用它們。(FunctionTharUseReferenncesToBase(Super)ClassesMustBeAbleToUseObjectsOfDerived(Sub)ClassesWithoutKnowingIt)2.里氏替換法則1/17/202332一個(gè)軟件如果使用的是一個(gè)父類的話,如果把該父類換成子類,它不能察覺(jué)出父類對(duì)象和子類對(duì)象的區(qū)別也就是凡是父類適用的地方子類也適用繼承只有滿足里氏代換原則才是合理的1/17/2023331/17/202334墨子論“取譬”“白馬,馬也;乘白馬,乘馬也。驪馬,馬也;乘驪馬,乘馬也?!苯忉專喊遵R、驪馬(黑馬)都是馬,既然馬可以騎,那么白馬和驪馬肯定也可以騎1/17/202335反過(guò)來(lái)的代換不成立子類適用的地方不要求父類一定能適用墨子又說(shuō)“娣,美人也,愛娣,非愛美人也......盜,人也,惡盜,非惡人也”妹妹是美女,哥哥喜歡妹妹,并不是因?yàn)橄矚g美女小偷是人,討厭小偷,并不討厭所有人1/17/202336PublicclassRectangle{privatedoublewidth;privatedoubleheigth;publicRectangle(doublew,doubleh){width=w;heigth=h;}publicvoidsetWidth(doublew){width=w;}publicvoidsetHeigth(doubleh){height=h;}publicdoublegetWidth(){returnwidth;}publicdoublegetHeigth(){returnheight;}publicdoublearea(){returnwidth*height;}}LSP例-矩形類1/17/202337正方形類Square正方形是矩形,因此Square類應(yīng)該從Rectangle類派生而來(lái)。思考1/17/202338PublicclassSquareextendsRectangle{publicSquare(doubles){super(s,s);}publicvoidsetWidth(doublew){super.setWidth(w);super.setHeight(w);}publicvoidsetHeight(doubleh){super.setWidth(h);super.setHeight(h);}}正方形類1/17/202339PublicclassTestRectangle{publicstaticvoidtestLSP(Rectangler){r.setWidth(4.0);r.setHeight(5.0);System.out.println(“Widthis4.0andHeightis5.0,Areais”+r.area());}測(cè)試類1/17/202340publicstaticvoidmain(Stringargs[]){Rectangler=newRectangle(1.0,1.0);Squares=newSquare(1.0);

testLSP(r);testLSP(s);}}測(cè)試1/17/202341編寫testLsp()方法的程序員做了一個(gè)合理的假設(shè),即改變Rectangle的寬而保持它的高不變。一個(gè)數(shù)學(xué)意義上的正方形可能是一個(gè)矩形,但是一個(gè)Square對(duì)象不是一個(gè)Rectangle對(duì)象,因?yàn)橐粋€(gè)Square對(duì)象的行為與一個(gè)Rectangle對(duì)象的行為是不一致的!(矩形僅包含get因?yàn)閟et不同)從行為上來(lái)說(shuō),一個(gè)Square不是一個(gè)Rectangle!一個(gè)Square對(duì)象與一個(gè)Rectangle對(duì)象之間不具有多態(tài)的特征。問(wèn)題1/17/2023421/17/202343Liskov替換法則(LSP)清楚地表明了ISA關(guān)系全部都是與行為有關(guān)的。為了保持LSP,所有子類必須符合使用基類的client所期望的行為。一個(gè)子類型不得具有比基類型更多的限制,可能這對(duì)于基類型來(lái)說(shuō)是合法的,但是可能會(huì)因?yàn)檫`背子類型的其中一個(gè)額外限制,從而違背了LSP!LSP保證一個(gè)子類總是能夠被用在其基類可以出現(xiàn)的地方小結(jié)1/17/202344抽象不應(yīng)當(dāng)依賴于細(xì)節(jié),細(xì)節(jié)應(yīng)當(dāng)依賴于抽象。(Abstationsshouldnotdependupondetails,Detailsshoulddependuponabstractions)3.依賴倒轉(zhuǎn)原則1/17/20234545設(shè)計(jì)原則:依賴倒置原則為什么說(shuō)“倒置”傳統(tǒng)的設(shè)計(jì)是抽象層依賴具體層傳統(tǒng)的重用,側(cè)重于具體層次的模塊,比如算法、數(shù)據(jù)結(jié)構(gòu)、函數(shù)庫(kù)因此軟件的高層模塊依賴低層模塊傳統(tǒng)的依賴方向1/17/20234646設(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)?1/17/20234747設(shè)計(jì)原則:針對(duì)接口編程如何做到“依賴倒置”?“Programtoaninterface,notanimplementation”設(shè)計(jì)原則:針對(duì)接口編程要針對(duì)接口編程不要針對(duì)實(shí)現(xiàn)編程1/17/20234848設(shè)計(jì)原則:針對(duì)接口編程“針對(duì)接口編程”的一些建議變量、參數(shù)、返回值等應(yīng)聲明為抽象類不要繼承非抽象類不要重載父類的非抽象方法當(dāng)然這些只是建議實(shí)際情況要權(quán)衡利弊1/17/202349不將變量聲明為某個(gè)特定的具體類的實(shí)例對(duì)象,而讓其遵從抽象類定義的接口。實(shí)現(xiàn)類僅實(shí)現(xiàn)接口,不添加方法。(Draw(shape*p)不要Cricle*pRectangle*pTriangle*p)針對(duì)接口編程1/17/202350任何變量都不應(yīng)該持有一個(gè)指向具體類的指針或引用任何類都不應(yīng)該從具體類派生任何方法都不應(yīng)該覆寫它的任何基類中已實(shí)現(xiàn)了的方法依賴于抽象1/17/202351Client不必知道其使用對(duì)象的具體所屬類。一個(gè)對(duì)象可以很容易地被(實(shí)現(xiàn)了相同接口的)的另一個(gè)對(duì)象所替換。對(duì)象間的連接不必硬綁定(hardwire)到一個(gè)具體類的對(duì)象上,因此增加了靈活性。松散耦合(loosenscoupling)。增加了重用的可能性。提高了(對(duì)象)組合的機(jī)率,因?yàn)楸话瑢?duì)象可以是任何實(shí)現(xiàn)了一個(gè)指定接口的類。使用接口的優(yōu)點(diǎn)1/17/202352如果一個(gè)類的實(shí)例必須使用另一個(gè)對(duì)象,而這個(gè)對(duì)象又屬于一個(gè)特定的類,那么復(fù)用性會(huì)受到損害。如果“使用”類只需使用“被使用”類的某些方法,而不是要求“被使用”類與“使用”類有“is-a”的關(guān)系,就可考慮,讓“被使用”類實(shí)現(xiàn)一個(gè)接口,“使用”類通過(guò)這個(gè)接口來(lái)使用需要的方法,從而限制了類之間的依賴。方案:為避免類之間因彼此使用而造成的耦合,讓它們通過(guò)接口間接使用。約束1/17/202353DIP可應(yīng)用于任何存在一個(gè)類向另一個(gè)類發(fā)送消息的地方。DIP應(yīng)用1/17/202354例1/17/202355例-找出潛在的抽象1/17/202356優(yōu)先使用(對(duì)象)組合,而非(類)繼承FavorCompositionOverInheritance4.組合復(fù)用原則1/17/202357容器類僅能通過(guò)被包含對(duì)象的接口來(lái)對(duì)其進(jìn)行訪問(wèn)?!昂诤小睆?fù)用,因?yàn)楸话瑢?duì)象的內(nèi)部細(xì)節(jié)對(duì)外是不可見。封裝性好。實(shí)現(xiàn)上的相互依賴性比較小。每一個(gè)類只專注于一項(xiàng)任務(wù)。通過(guò)獲取指向其它的具有相同類型的對(duì)象引用,可以在運(yùn)行期間動(dòng)態(tài)地定義(對(duì)象的)組合。組合優(yōu)點(diǎn)1/17/202358從而導(dǎo)致系統(tǒng)中的對(duì)象過(guò)多。為了能將多個(gè)不同的對(duì)象作為組合塊(compositionblock)來(lái)使用,必須仔細(xì)地對(duì)接口進(jìn)行定義。組合缺點(diǎn)1/17/202359(類)繼承是一種通過(guò)擴(kuò)展一個(gè)已有對(duì)象的實(shí)現(xiàn),從而獲得新功能的復(fù)用方法。泛化類(超類)可以顯式地捕獲那些公共的屬性和方法。特殊類(子類)則通過(guò)附加屬性和方法來(lái)進(jìn)行實(shí)現(xiàn)的擴(kuò)展繼承1/17/202360容易進(jìn)行新的實(shí)現(xiàn),因?yàn)槠浯蠖鄶?shù)可繼承而來(lái)。易于修改或擴(kuò)展那些被復(fù)用的實(shí)現(xiàn)。繼承優(yōu)點(diǎn)1/17/202361破壞了封裝性,因?yàn)檫@會(huì)將父類的實(shí)現(xiàn)細(xì)節(jié)暴露給子類?!鞍缀小睆?fù)用,因?yàn)楦割惖膬?nèi)部細(xì)節(jié)對(duì)于子類而言通常是可見的。當(dāng)父類的實(shí)現(xiàn)更改時(shí),子類也不得不會(huì)隨之更改。從父類繼承來(lái)的實(shí)現(xiàn)將不能在運(yùn)行期間進(jìn)行改變。繼承缺點(diǎn)1/17/202362僅當(dāng)下列的所有標(biāo)準(zhǔn)被滿足時(shí),方可使用繼承:子類表達(dá)了“是一個(gè)…的特殊類型”,而非“是一個(gè)由…所扮演的角色”。子類的一個(gè)實(shí)例永遠(yuǎn)不需要轉(zhuǎn)化(transmute)為其它類的一個(gè)對(duì)象。子類是對(duì)其父類的職責(zé)(responsibility)進(jìn)行擴(kuò)展,而非重寫或廢除(nullify)。子類沒(méi)有對(duì)那些僅作為一個(gè)工具類(utilityclass)的功能進(jìn)行擴(kuò)展。Coad規(guī)則1/17/202363例1/17/202364組合與繼承都是重要的重用方法在OO開發(fā)的早期,繼承被過(guò)度地使用隨著時(shí)間的發(fā)展,我們發(fā)現(xiàn)優(yōu)先使用組合可以獲得重用性與簡(jiǎn)單性更佳的設(shè)計(jì)當(dāng)然可以通過(guò)繼承,以擴(kuò)充可用的組合類集。因此組合與繼承可以一起工作但是我們的基本法則是:優(yōu)先使用對(duì)象組合,而非(類)繼承小結(jié)1/17/202365LawofDemeter又稱最少知識(shí)原則,一個(gè)對(duì)象應(yīng)該對(duì)其他對(duì)象盡可能少的了解。5.迪米特法則(LoD)1/17/202366控制信息過(guò)載,提高封裝能力。1. 創(chuàng)建弱耦合類,利于復(fù)用2. 降低成員訪問(wèn)權(quán)限3. 設(shè)計(jì)不變類廣義1/17/202367如果兩個(gè)類不必彼此通信,那么這兩個(gè)類就不應(yīng)當(dāng)發(fā)生直接的相互作用。如果其中的一個(gè)類需要調(diào)用另一個(gè)類的某一個(gè)方法的話,可通過(guò)第三者轉(zhuǎn)發(fā)這個(gè)調(diào)用。狹義1/17/202368朋友圈1/17/2023691/17/202370VoidSomeone::Operation1(Friendfriend){Strangerstranger=vide();stranger.Operation3();}StrangerFriend::provide(){returnstran

溫馨提示

  • 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)論