提高面向?qū)ο笤O(shè)計復(fù)用性的設(shè)計原則課件_第1頁
提高面向?qū)ο笤O(shè)計復(fù)用性的設(shè)計原則課件_第2頁
提高面向?qū)ο笤O(shè)計復(fù)用性的設(shè)計原則課件_第3頁
提高面向?qū)ο笤O(shè)計復(fù)用性的設(shè)計原則課件_第4頁
提高面向?qū)ο笤O(shè)計復(fù)用性的設(shè)計原則課件_第5頁
已閱讀5頁,還剩121頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

提高面向?qū)ο笤O(shè)計復(fù)用性的設(shè)計原則面向?qū)ο蟮脑O(shè)計原則1/3/20231提高面向?qū)ο笤O(shè)計復(fù)用性的設(shè)計原則面向?qū)ο蟮脑O(shè)計原則12/28設(shè)計目標可擴展性(Extensibility):新功能易加入系統(tǒng)。靈活性(Flexibility):允許代碼修改平穩(wěn)發(fā)生,不會涉及很多其他模塊??刹迦胄?Pluggability):容易將一個類換為另一個具有同樣接口的類。1/3/20232設(shè)計目標可擴展性(Extensibility):新功能易加入軟件復(fù)用重要性較高的生產(chǎn)率較高的軟件質(zhì)量恰當使用復(fù)用,可改善系統(tǒng)的可維護性1/3/20233軟件復(fù)用重要性較高的生產(chǎn)率12/28/20223使一個系統(tǒng)可在更高的層次上提供了可復(fù)用性抽象化和繼承:使概念和定義可復(fù)用多態(tài):使實現(xiàn)和應(yīng)用可復(fù)用抽象化和封裝:可保持和促進系統(tǒng)的可維護性面向?qū)ο笤O(shè)計1/3/20234使一個系統(tǒng)可在更高的層次上提供了可復(fù)用性面向?qū)ο笤O(shè)計12/2抽象層次是一個應(yīng)用系統(tǒng)作戰(zhàn)略性判斷和決定的地方,那么抽象層次就應(yīng)當是較為穩(wěn)定的,應(yīng)當是復(fù)用的重點。復(fù)用的焦點不再集中在函數(shù)和算法等具體實現(xiàn)細節(jié)上,而是集中在最重要的含有宏觀商業(yè)邏輯的抽象層次上。既然如果抽象層次的模塊相對獨立于具體層次的模塊的話,那么具體層次內(nèi)部的變化就不會影響到抽象層次的結(jié)構(gòu),所以抽象層次的復(fù)用就會較為容易。復(fù)用1/3/20235抽象層次是一個應(yīng)用系統(tǒng)作戰(zhàn)略性判斷和決定的地方,那么抽象層次面向?qū)ο笤O(shè)計中,可維護性復(fù)用是以設(shè)計原則和設(shè)計模式為基礎(chǔ)的。面向?qū)ο髲?fù)用1/3/20236面向?qū)ο笤O(shè)計中,可維護性復(fù)用是以設(shè)計原則和設(shè)計模式為基礎(chǔ)的。1.開閉原則OCP:Open-ClosedPrinciple2. 里氏替換原則LSP:LiskovSubstitutionPrinciple3. 依賴倒轉(zhuǎn)原則DIP:DependencyInversionPrinciple4. 接口隔離原則ISP:InterfaceSegregationPrinciple5. 組合復(fù)用原則CRP:CompositoinResusePrinciple6. 迪米特法則LoD:LawofDemeter7.單一職責原則(SRP)面向?qū)ο笤O(shè)計原則1/3/202371.開閉原則OCP:Open-ClosedPrincipl軟件組成實體應(yīng)該是對擴展可擴展的,但是對修改是關(guān)閉的。(SoftwareEntitiesShouldBeOpenForExtension,ButClosedForModification)1.開-閉原則OCP1/3/20238軟件組成實體應(yīng)該是對擴展可擴展的,但是對修改是關(guān)閉的。(S開放-封閉法則認為應(yīng)該試圖去設(shè)計出永遠也不需要改變的模塊。關(guān)鍵在于抽象化:可給系統(tǒng)定義一個一勞永逸,不再更改的抽象設(shè)計,此設(shè)計允許有無窮無盡的行為在實現(xiàn)層被實現(xiàn)。抽象層預(yù)見所有擴展。PC外設(shè)開-閉原則1/3/20239開放-封閉法則認為應(yīng)該試圖去設(shè)計出永遠也不需要改變的模塊。開一個軟件系統(tǒng)的所有模塊不可能都滿足OCP,但是應(yīng)該努力最小化這些不滿足OCP的模塊數(shù)量。開-閉原則1/3/202310一個軟件系統(tǒng)的所有模塊不可能都滿足OCP,但是應(yīng)該努力最小化PublicclassPart{privatedoublebasePrice;publicvoidsetPrice(doubleprice){basePrice=price;}publicdoublegetPrice(){returnbasePrice;}}OCP例-類1/3/202311PublicclassPart{OCP例-類12/28/Publicdoubletotalprice(Part[]parts){doubletotal=0.0;for(inti=0;i<parts.length;i++){total+=parts[i].getPrice();}returntotal;}OCP例-某類方法1/3/202312Publicdoubletotalprice(Part[內(nèi)存折扣?思考1/3/202313內(nèi)存折扣?思考12/28/202213Publicdoubletotalprice(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/3/202314Publicdoubletotalprice(Part[符合OCP嗎?思考1/3/202315符合OCP嗎?思考12/28/202215PublicclassMemoryextendsPart{publicdoublegetPrice(){returnbasePrice*0.9;}}方法?1/3/202316PublicclassMemoryextendsPa采用一個PricePolicy類,通過對其進行繼承以提供不同的計價策略更好的方法?1/3/202317采用一個PricePolicy類,通過對其進行繼承以提供不同PublicclassPart{privatePricePolicypricePolicy;publicvoidsetPricePolicy(PricePolicypolicy){pricePolicy=policy;}publicvoidsetPrice(doubleprice){pricePolicy.setPrice(price);}publicdoublegetPrice(){returnpricePolicy.getPrice();}}方法1/3/202318PublicclassPart{方法12/28/2022PublicclassPricePolicy{privatedoublebasePrice;publicvoidsetPrice(doubleprice){basePrice=price;}publicdoublegetPrice(){returnbasePrice;}}價格策略1/3/202319PublicclassPricePolicy{價格策略1PublicclassSaleextendsPricePolicy{privatedoublediscount;publicvoidsetDiscount(doublediscount){this.discount=discount;}publicdoublegetPrice(){returnbasePrice*discount;}}銷售策略1/3/202320PublicclassSaleextendsPric符合OCP了嗎?思考1/3/202321符合OCP了嗎?思考12/28/202221應(yīng)用實例我們有一個需要在標準的GUI上繪制園和正方形的應(yīng)用程序。圓和正方形必須要按照特定的順序繪制。我們將創(chuàng)建一個列表,列表由按照適當?shù)捻樞蚺帕械膱@和正方形組成,程序遍歷該列表,一次繪制出每個圓和正方形。1/3/202322應(yīng)用實例我們有一個需要在標準的GUI上繪制園和正方形的應(yīng)用程先考慮違反OCP的過程化方法定義一個DrawAllShapes函數(shù)使用SWITCH來分支繪制圖形為什么不符合OCP?因為它對于新的形狀類型的添加不是封閉的每增加一種新的形狀類型,都必須要更改這個函數(shù)1/3/202323先考慮違反OCP的過程化方法12/28/202223這樣的設(shè)計糟糕在哪里?增加形狀會導(dǎo)致所有的程序、變量重新編譯和部署想在另一個程序中復(fù)用DrawAllShape這個函數(shù)時,都必須要附帶上Square和Circle,即時那個程序不需要它們。1/3/202324這樣的設(shè)計糟糕在哪里?12/28/202224怎樣遵循OCP編寫一個shape抽象類這個類僅有一個抽象方法draw()所有形狀都從這個類派生當繪制一種新的形狀,只需要增加一個新的shape類的派生類。而DrawAllShapes函數(shù)并不需要改變。1/3/202325怎樣遵循OCP編寫一個shape抽象類12/28/20222使用指向基類(超類)的引用的函數(shù),必須能夠在不知道具體派生類(子類)對象類型的情況下使用它們。(FunctionTharUseReferenncesToBase(Super)ClassesMustBeAbleToUseObjectsOfDerived(Sub)ClassesWithoutKnowingIt)2.里氏替換法則1/3/202326使用指向基類(超類)的引用的函數(shù),必須能夠在不知道具體派生類PublicclassRectangle{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/3/202327PublicclassRectangle{LSP例-矩形正方形類Square正方形是矩形,因此Square類應(yīng)該從Rectangle類派生而來。思考1/3/202328正方形類Square思考12/28/202228PublicclassSquareextendsRectangle{publicSquare(doubles){super(s,s);}publicvoidsetWidth(doublew){super.setWidth(w);super.setHeight(w);}publicvoidsetHeight(doubleh){super.setWidth(h);super.setHeight(h);}}正方形類1/3/202329PublicclassSquareextendsRePublicclassTestRectangle{publicstaticvoidtestLSP(Rectangler){r.setWidth(4.0);r.setHeight(5.0);System.out.println(“Widthis4.0andHeightis5.0,Areais”+r.area());}測試類1/3/202330PublicclassTestRectangle{測試類publicstaticvoidmain(Stringargs[]){Rectangler=newRectangle(1.0,1.0);Squares=newSquare(1.0);

testLSP(r);testLSP(s);}}測試1/3/202331publicstaticvoidmain(String編寫testLsp()方法的程序員做了一個合理的假設(shè),即改變Rectangle的寬而保持它的高不變。一個數(shù)學(xué)意義上的正方形可能是一個矩形,但是一個Square對象不是一個Rectangle對象,因為一個Square對象的行為與一個Rectangle對象的行為是不一致的!(矩形僅包含get因為set不同)從行為上來說,一個Square不是一個Rectangle!一個Square對象與一個Rectangle對象之間不具有多態(tài)的特征。問題1/3/202332編寫testLsp()方法的程序員做了一個合理的假設(shè),即改變Liskov替換法則(LSP)清楚地表明了ISA關(guān)系全部都是與行為有關(guān)的。為了保持LSP,所有子類必須符合使用基類的client所期望的行為。一個子類型不得具有比基類型更多的限制,可能這對于基類型來說是合法的,但是可能會因為違背子類型的其中一個額外限制,從而違背了LSP!LSP保證一個子類總是能夠被用在其基類可以出現(xiàn)的地方小結(jié)1/3/202333Liskov替換法則(LSP)清楚地表明了ISA關(guān)系全部都是抽象不應(yīng)當依賴于細節(jié),細節(jié)應(yīng)當依賴于抽象。(Abstationsshouldnotdependupondetails,Detailsshoulddependuponabstractions)3.依賴倒轉(zhuǎn)原則1/3/202334抽象不應(yīng)當依賴于細節(jié),細節(jié)應(yīng)當依賴于抽象。3.依賴倒轉(zhuǎn)原則1針對接口編程,而非實現(xiàn)ProgramToAnInterface,NotAnImplementationDIP1/3/202335針對接口編程,而非實現(xiàn)DIP12/28/202235Client不必知道其使用對象的具體所屬類。一個對象可以很容易地被(實現(xiàn)了相同接口的)的另一個對象所替換。對象間的連接不必硬綁定(hardwire)到一個具體類的對象上,因此增加了靈活性。松散藕合(loosenscoupling)。增加了重用的可能性。提高了(對象)組合的機率,因為被包含對象可以是任何實現(xiàn)了一個指定接口的類。使用接口的優(yōu)點1/3/202336Client不必知道其使用對象的具體所屬類。使用接口的優(yōu)點1不將變量聲明為某個特定的具體類的實例對象,而讓其遵從抽象類定義的接口。實現(xiàn)類僅實現(xiàn)接口,不添加方法。(Draw(shape*p)不要Cricle*pRectangle*pTriangle*p)針對接口編程1/3/202337不將變量聲明為某個特定的具體類的實例對象,而讓其遵從抽象類定任何變量都不應(yīng)該持有一個指向具體類的指針或引用任何類都不應(yīng)該從具體類派生任何方法都不應(yīng)該覆寫它的任何基類中已實現(xiàn)了的方法依賴于抽象1/3/202338任何變量都不應(yīng)該持有一個指向具體類的指針或引用依賴于抽象12如果一個類的實例必須使用另一個對象,而這個對象又屬于一個特定的類,那么復(fù)用性會受到損害。如果“使用”類只需使用“被使用”類的某些方法,而不是要求“被使用”類與“使用”類有“is-a”的關(guān)系,就可考慮,讓“被使用”類實現(xiàn)一個接口,“使用”類通過這個接口來使用需要的方法,從而限制了類之間的依賴。方案:為避免類之間因彼此使用而造成的耦合,讓它們通過接口間接使用。約束1/3/202339如果一個類的實例必須使用另一個對象,而這個對象又屬于一個特定DIP可應(yīng)用于任何存在一個類向另一個類發(fā)送消息的地方。DIP應(yīng)用1/3/202340DIP可應(yīng)用于任何存在一個類向另一個類發(fā)送消息的地方。DIP例1/3/202341例12/28/202241例-找出潛在的抽象1/3/202342例-找出潛在的抽象12/28/202242實例考慮一個控制熔爐調(diào)節(jié)器的軟件,該軟件可以從一個IO通道中讀取當前的溫度,并通過向另一個IO通道發(fā)送命令來指示熔爐的開或者關(guān)。1/3/202343實例12/28/202243優(yōu)先使用(對象)組合,而非(類)繼承FavorCompositionOverInheritance4.組合復(fù)用原則1/3/202344優(yōu)先使用(對象)組合,而非(類)繼承4.組合復(fù)用原則12/2容器類僅能通過被包含對象的接口來對其進行訪問。“黑盒”復(fù)用,因為被包含對象的內(nèi)部細節(jié)對外是不可見。封裝性好。實現(xiàn)上的相互依賴性比較小。每一個類只專注于一項任務(wù)。通過獲取指向其它的具有相同類型的對象引用,可以在運行期間動態(tài)地定義(對象的)組合。組合優(yōu)點1/3/202345容器類僅能通過被包含對象的接口來對其進行訪問。組合優(yōu)點12/從而導(dǎo)致系統(tǒng)中的對象過多。為了能將多個不同的對象作為組合塊(compositionblock)來使用,必須仔細地對接口進行定義。組合缺點1/3/202346從而導(dǎo)致系統(tǒng)中的對象過多。組合缺點12/28/202246(類)繼承是一種通過擴展一個已有對象的實現(xiàn),從而獲得新功能的復(fù)用方法。泛化類(超類)可以顯式地捕獲那些公共的屬性和方法。特殊類(子類)則通過附加屬性和方法來進行實現(xiàn)的擴展繼承1/3/202347(類)繼承是一種通過擴展一個已有對象的實現(xiàn),從而獲得新功能的容易進行新的實現(xiàn),因為其大多數(shù)可繼承而來。易于修改或擴展那些被復(fù)用的實現(xiàn)。繼承優(yōu)點1/3/202348容易進行新的實現(xiàn),因為其大多數(shù)可繼承而來。繼承優(yōu)點12/28破壞了封裝性,因為這會將父類的實現(xiàn)細節(jié)暴露給子類?!鞍缀小睆?fù)用,因為父類的內(nèi)部細節(jié)對于子類而言通常是可見的。當父類的實現(xiàn)更改時,子類也不得不會隨之更改。從父類繼承來的實現(xiàn)將不能在運行期間進行改變。繼承缺點1/3/202349破壞了封裝性,因為這會將父類的實現(xiàn)細節(jié)暴露給子類。繼承缺點1僅當下列的所有標準被滿足時,方可使用繼承:子類表達了“是一個…的特殊類型”,而非“是一個由…所扮演的角色”。子類的一個實例永遠不需要轉(zhuǎn)化(transmute)為其它類的一個對象。子類是對其父類的職責(responsibility)進行擴展,而非重寫或廢除(nullify)。子類沒有對那些僅作為一個工具類(utilityclass)的功能進行擴展。Coad規(guī)則1/3/202350僅當下列的所有標準被滿足時,方可使用繼承:Coad規(guī)則12/例1/3/202351例12/28/202251組合與繼承都是重要的重用方法在OO開發(fā)的早期,繼承被過度地使用隨著時間的發(fā)展,我們發(fā)現(xiàn)優(yōu)先使用組合可以獲得重用性與簡單性更佳的設(shè)計當然可以通過繼承,以擴充可用的組合類集。因此組合與繼承可以一起工作但是我們的基本法則是:優(yōu)先使用對象組合,而非(類)繼承小結(jié)1/3/202352組合與繼承都是重要的重用方法小結(jié)12/28/202252LawofDemeter又稱最少知識原則,一個對象應(yīng)該對其他對象盡可能少的了解。5.迪米特法則(LoD)1/3/202353LawofDemeter5.迪米特法則(LoD)12/控制信息過載,提高封裝能力。1. 創(chuàng)建弱耦合類,利于復(fù)用2. 降低成員訪問權(quán)限3. 設(shè)計不變類廣義1/3/202354控制信息過載,提高封裝能力。廣義12/28/202254如果兩個類不必彼此通信,那么這兩個類就不應(yīng)當發(fā)生直接的相互作用。如果其中的一個類需要調(diào)用另一個類的某一個方法的話,可通過第三者轉(zhuǎn)發(fā)這個調(diào)用。狹義1/3/202355如果兩個類不必彼此通信,那么這兩個類就不應(yīng)當發(fā)生直接的相互作VoidSomeone::Operation1(Friendfriend){Strangerstranger=vide();stranger.Operation3();}StrangerFriend::provide(){returnstranger;}例1/3/202356VoidSomeone::Operation1(Frien滿足LOD嗎?思考1/3/202357滿足LOD嗎?思考12/28/202257使用多個專門的接口比使用單一的總接口好。一個類對另一個類的依賴性應(yīng)建立在最小的接口上。6.接口隔離原則(ISP)1/3/202358使用多個專門的接口比使用單一的總接口好。6.接口隔離原則(定制服務(wù):為同一角色提供寬窄不同的接口。(承諾多,維護難)ISP1/3/202359定制服務(wù):為同一角色提供寬窄不同的接口。ISP12/28/2如果類的接口不是內(nèi)聚的,就表示該類具有“胖”的接口。ISP建議客戶程序不應(yīng)該看到它們作為單一的類存在??蛻舫绦蚩吹降膽?yīng)該是多個具有內(nèi)聚接口的抽象基類。1/3/202360如果類的接口不是內(nèi)聚的,就表示該類具有“胖”的接口。12/2現(xiàn)在,考慮自動取款機(ATM)ATM需要一個非常靈活的用戶界面。它的輸出信息需要被轉(zhuǎn)換成許多不同的語言。輸出信息可能被顯示在屏幕上,或者通過語音器說出來。顯然界面需要創(chuàng)建一個抽象基類同樣可以把每個ATM可以執(zhí)行的操作封裝為類Transaction的派生類。有DepositTransaction,WithdrawTransaction以及TransferTransaction,每個類都調(diào)用UI的方法。如何設(shè)計是違反LSP和遵守LSP?1/3/202361現(xiàn)在,考慮自動取款機(ATM)12/28/202261單一職責原則(SRP)RectangleDraw()Area()ComputationalGeometryApplicationGraphicalApplication1/3/202362單一職責原則(SRP)RectangleDraw()CompModem示例Dial()Hangup()Send()Receive()卻顯示兩個職責連接管理數(shù)據(jù)通信1/3/202363Modem示例12/28/202263提高面向?qū)ο笤O(shè)計復(fù)用性的設(shè)計原則面向?qū)ο蟮脑O(shè)計原則1/3/202364提高面向?qū)ο笤O(shè)計復(fù)用性的設(shè)計原則面向?qū)ο蟮脑O(shè)計原則12/28設(shè)計目標可擴展性(Extensibility):新功能易加入系統(tǒng)。靈活性(Flexibility):允許代碼修改平穩(wěn)發(fā)生,不會涉及很多其他模塊。可插入性(Pluggability):容易將一個類換為另一個具有同樣接口的類。1/3/202365設(shè)計目標可擴展性(Extensibility):新功能易加入軟件復(fù)用重要性較高的生產(chǎn)率較高的軟件質(zhì)量恰當使用復(fù)用,可改善系統(tǒng)的可維護性1/3/202366軟件復(fù)用重要性較高的生產(chǎn)率12/28/20223使一個系統(tǒng)可在更高的層次上提供了可復(fù)用性抽象化和繼承:使概念和定義可復(fù)用多態(tài):使實現(xiàn)和應(yīng)用可復(fù)用抽象化和封裝:可保持和促進系統(tǒng)的可維護性面向?qū)ο笤O(shè)計1/3/202367使一個系統(tǒng)可在更高的層次上提供了可復(fù)用性面向?qū)ο笤O(shè)計12/2抽象層次是一個應(yīng)用系統(tǒng)作戰(zhàn)略性判斷和決定的地方,那么抽象層次就應(yīng)當是較為穩(wěn)定的,應(yīng)當是復(fù)用的重點。復(fù)用的焦點不再集中在函數(shù)和算法等具體實現(xiàn)細節(jié)上,而是集中在最重要的含有宏觀商業(yè)邏輯的抽象層次上。既然如果抽象層次的模塊相對獨立于具體層次的模塊的話,那么具體層次內(nèi)部的變化就不會影響到抽象層次的結(jié)構(gòu),所以抽象層次的復(fù)用就會較為容易。復(fù)用1/3/202368抽象層次是一個應(yīng)用系統(tǒng)作戰(zhàn)略性判斷和決定的地方,那么抽象層次面向?qū)ο笤O(shè)計中,可維護性復(fù)用是以設(shè)計原則和設(shè)計模式為基礎(chǔ)的。面向?qū)ο髲?fù)用1/3/202369面向?qū)ο笤O(shè)計中,可維護性復(fù)用是以設(shè)計原則和設(shè)計模式為基礎(chǔ)的。1.開閉原則OCP:Open-ClosedPrinciple2. 里氏替換原則LSP:LiskovSubstitutionPrinciple3. 依賴倒轉(zhuǎn)原則DIP:DependencyInversionPrinciple4. 接口隔離原則ISP:InterfaceSegregationPrinciple5. 組合復(fù)用原則CRP:CompositoinResusePrinciple6. 迪米特法則LoD:LawofDemeter7.單一職責原則(SRP)面向?qū)ο笤O(shè)計原則1/3/2023701.開閉原則OCP:Open-ClosedPrincipl軟件組成實體應(yīng)該是對擴展可擴展的,但是對修改是關(guān)閉的。(SoftwareEntitiesShouldBeOpenForExtension,ButClosedForModification)1.開-閉原則OCP1/3/202371軟件組成實體應(yīng)該是對擴展可擴展的,但是對修改是關(guān)閉的。(S開放-封閉法則認為應(yīng)該試圖去設(shè)計出永遠也不需要改變的模塊。關(guān)鍵在于抽象化:可給系統(tǒng)定義一個一勞永逸,不再更改的抽象設(shè)計,此設(shè)計允許有無窮無盡的行為在實現(xiàn)層被實現(xiàn)。抽象層預(yù)見所有擴展。PC外設(shè)開-閉原則1/3/202372開放-封閉法則認為應(yīng)該試圖去設(shè)計出永遠也不需要改變的模塊。開一個軟件系統(tǒng)的所有模塊不可能都滿足OCP,但是應(yīng)該努力最小化這些不滿足OCP的模塊數(shù)量。開-閉原則1/3/202373一個軟件系統(tǒng)的所有模塊不可能都滿足OCP,但是應(yīng)該努力最小化PublicclassPart{privatedoublebasePrice;publicvoidsetPrice(doubleprice){basePrice=price;}publicdoublegetPrice(){returnbasePrice;}}OCP例-類1/3/202374PublicclassPart{OCP例-類12/28/Publicdoubletotalprice(Part[]parts){doubletotal=0.0;for(inti=0;i<parts.length;i++){total+=parts[i].getPrice();}returntotal;}OCP例-某類方法1/3/202375Publicdoubletotalprice(Part[內(nèi)存折扣?思考1/3/202376內(nèi)存折扣?思考12/28/202213Publicdoubletotalprice(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/3/202377Publicdoubletotalprice(Part[符合OCP嗎?思考1/3/202378符合OCP嗎?思考12/28/202215PublicclassMemoryextendsPart{publicdoublegetPrice(){returnbasePrice*0.9;}}方法?1/3/202379PublicclassMemoryextendsPa采用一個PricePolicy類,通過對其進行繼承以提供不同的計價策略更好的方法?1/3/202380采用一個PricePolicy類,通過對其進行繼承以提供不同PublicclassPart{privatePricePolicypricePolicy;publicvoidsetPricePolicy(PricePolicypolicy){pricePolicy=policy;}publicvoidsetPrice(doubleprice){pricePolicy.setPrice(price);}publicdoublegetPrice(){returnpricePolicy.getPrice();}}方法1/3/202381PublicclassPart{方法12/28/2022PublicclassPricePolicy{privatedoublebasePrice;publicvoidsetPrice(doubleprice){basePrice=price;}publicdoublegetPrice(){returnbasePrice;}}價格策略1/3/202382PublicclassPricePolicy{價格策略1PublicclassSaleextendsPricePolicy{privatedoublediscount;publicvoidsetDiscount(doublediscount){this.discount=discount;}publicdoublegetPrice(){returnbasePrice*discount;}}銷售策略1/3/202383PublicclassSaleextendsPric符合OCP了嗎?思考1/3/202384符合OCP了嗎?思考12/28/202221應(yīng)用實例我們有一個需要在標準的GUI上繪制園和正方形的應(yīng)用程序。圓和正方形必須要按照特定的順序繪制。我們將創(chuàng)建一個列表,列表由按照適當?shù)捻樞蚺帕械膱@和正方形組成,程序遍歷該列表,一次繪制出每個圓和正方形。1/3/202385應(yīng)用實例我們有一個需要在標準的GUI上繪制園和正方形的應(yīng)用程先考慮違反OCP的過程化方法定義一個DrawAllShapes函數(shù)使用SWITCH來分支繪制圖形為什么不符合OCP?因為它對于新的形狀類型的添加不是封閉的每增加一種新的形狀類型,都必須要更改這個函數(shù)1/3/202386先考慮違反OCP的過程化方法12/28/202223這樣的設(shè)計糟糕在哪里?增加形狀會導(dǎo)致所有的程序、變量重新編譯和部署想在另一個程序中復(fù)用DrawAllShape這個函數(shù)時,都必須要附帶上Square和Circle,即時那個程序不需要它們。1/3/202387這樣的設(shè)計糟糕在哪里?12/28/202224怎樣遵循OCP編寫一個shape抽象類這個類僅有一個抽象方法draw()所有形狀都從這個類派生當繪制一種新的形狀,只需要增加一個新的shape類的派生類。而DrawAllShapes函數(shù)并不需要改變。1/3/202388怎樣遵循OCP編寫一個shape抽象類12/28/20222使用指向基類(超類)的引用的函數(shù),必須能夠在不知道具體派生類(子類)對象類型的情況下使用它們。(FunctionTharUseReferenncesToBase(Super)ClassesMustBeAbleToUseObjectsOfDerived(Sub)ClassesWithoutKnowingIt)2.里氏替換法則1/3/202389使用指向基類(超類)的引用的函數(shù),必須能夠在不知道具體派生類PublicclassRectangle{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/3/202390PublicclassRectangle{LSP例-矩形正方形類Square正方形是矩形,因此Square類應(yīng)該從Rectangle類派生而來。思考1/3/202391正方形類Square思考12/28/202228PublicclassSquareextendsRectangle{publicSquare(doubles){super(s,s);}publicvoidsetWidth(doublew){super.setWidth(w);super.setHeight(w);}publicvoidsetHeight(doubleh){super.setWidth(h);super.setHeight(h);}}正方形類1/3/202392PublicclassSquareextendsRePublicclassTestRectangle{publicstaticvoidtestLSP(Rectangler){r.setWidth(4.0);r.setHeight(5.0);System.out.println(“Widthis4.0andHeightis5.0,Areais”+r.area());}測試類1/3/202393PublicclassTestRectangle{測試類publicstaticvoidmain(Stringargs[]){Rectangler=newRectangle(1.0,1.0);Squares=newSquare(1.0);

testLSP(r);testLSP(s);}}測試1/3/202394publicstaticvoidmain(String編寫testLsp()方法的程序員做了一個合理的假設(shè),即改變Rectangle的寬而保持它的高不變。一個數(shù)學(xué)意義上的正方形可能是一個矩形,但是一個Square對象不是一個Rectangle對象,因為一個Square對象的行為與一個Rectangle對象的行為是不一致的!(矩形僅包含get因為set不同)從行為上來說,一個Square不是一個Rectangle!一個Square對象與一個Rectangle對象之間不具有多態(tài)的特征。問題1/3/202395編寫testLsp()方法的程序員做了一個合理的假設(shè),即改變Liskov替換法則(LSP)清楚地表明了ISA關(guān)系全部都是與行為有關(guān)的。為了保持LSP,所有子類必須符合使用基類的client所期望的行為。一個子類型不得具有比基類型更多的限制,可能這對于基類型來說是合法的,但是可能會因為違背子類型的其中一個額外限制,從而違背了LSP!LSP保證一個子類總是能夠被用在其基類可以出現(xiàn)的地方小結(jié)1/3/202396Liskov替換法則(LSP)清楚地表明了ISA關(guān)系全部都是抽象不應(yīng)當依賴于細節(jié),細節(jié)應(yīng)當依賴于抽象。(Abstationsshouldnotdependupondetails,Detailsshoulddependuponabstractions)3.依賴倒轉(zhuǎn)原則1/3/202397抽象不應(yīng)當依賴于細節(jié),細節(jié)應(yīng)當依賴于抽象。3.依賴倒轉(zhuǎn)原則1針對接口編程,而非實現(xiàn)ProgramToAnInterface,NotAnImplementationDIP1/3/202398針對接口編程,而非實現(xiàn)DIP12/28/202235Client不必知道其使用對象的具體所屬類。一個對象可以很容易地被(實現(xiàn)了相同接口的)的另一個對象所替換。對象間的連接不必硬綁定(hardwire)到一個具體類的對象上,因此增加了靈活性。松散藕合(loosenscoupling)。增加了重用的可能性。提高了(對象)組合的機率,因為被包含對象可以是任何實現(xiàn)了一個指定接口的類。使用接口的優(yōu)點1/3/202399Client不必知道其使用對象的具體所屬類。使用接口的優(yōu)點1不將變量聲明為某個特定的具體類的實例對象,而讓其遵從抽象類定義的接口。實現(xiàn)類僅實現(xiàn)接口,不添加方法。(Draw(shape*p)不要Cricle*pRectangle*pTriangle*p)針對接口編程1/3/2023100不將變量聲明為某個特定的具體類的實例對象,而讓其遵從抽象類定任何變量都不應(yīng)該持有一個指向具體類的指針或引用任何類都不應(yīng)該從具體類派生任何方法都不應(yīng)該覆寫它的任何基類中已實現(xiàn)了的方法依賴于抽象1/3/2023101任何變量都不應(yīng)該持有一個指向具體類的指針或引用依賴于抽象12如果一個類的實例必須使用另一個對象,而這個對象又屬于一個特定的類,那么復(fù)用性會受到損害。如果“使用”類只需使用“被使用”類的某些方法,而不是要求“被使用”類與“使用”類有“is-a”的關(guān)系,就可考慮,讓“被使用”類實現(xiàn)一個接口,“使用”類通過這個接口來使用需要的方法,從而限制了類之間的依賴。方案:為避免類之間因彼此使用而造成的耦合,讓它們通過接口間接使用。約束1/3/2023102如果一個類的實例必須使用另一個對象,而這個對象又屬于一個特定DIP可應(yīng)用于任何存在一個類向另一個類發(fā)送消息的地方。DIP應(yīng)用1/3/2023103DIP可應(yīng)用于任何存在一個類向另一個類發(fā)送消息的地方。DIP例1/3/2023104例12/28/202241例-找出潛在的抽象1/3/2023105例-找出潛在的抽象12/28/202242實例考慮一個控制熔爐調(diào)節(jié)器的軟件,該軟件可以從一個IO通道中讀取當前的溫度,并通過向另一個IO通道發(fā)送命令來指示熔爐的開或者關(guān)。1/3/2023106實例12/28/202243優(yōu)先使用(對象)組合,而非(類)繼承FavorCompositionOverInheritance4.組合復(fù)用原則1/3/2023107優(yōu)先使用(對象)組合,而非(類)繼承4.組合復(fù)用原則12/2容器類僅能通過被包含對象的接口來對其進行訪問?!昂诤小睆?fù)用,因為被包含對象的內(nèi)部細節(jié)對外是不可見。封裝性好。實現(xiàn)上的相互依賴性比較小。每一個類只專注于一項任務(wù)。通過獲取指向其它的具有相同類型的對象引用,可以在運行期間動態(tài)地定義(對象的)組合。組合優(yōu)點1/3/2023108容器類僅能通過被包含對象的接口來對其進行訪問。組合優(yōu)點12/從而導(dǎo)致系統(tǒng)中的對象過多。為了能將多個不同的對象作為組合塊(compositionblock)來使用,必須仔細地對接口進行定義。組合缺點1/3/2023109從而導(dǎo)致系統(tǒng)中的對象過多。組合缺點12/28/202246(類)繼承是一種通過擴展一個已有對象的實現(xiàn),從而獲得新功能的復(fù)用方法。泛化類(超類)可以顯式地捕獲那些公共的屬性和方法。特殊類(子類)則通過附加屬性和方法來進行實現(xiàn)的擴展繼承1/3/2023110(類)繼承是一種通過擴展一個已有對象的實現(xiàn),從而獲得新功能的容易進行新的實現(xiàn),因為其大多數(shù)可繼承而來。易于修改或擴展那些被復(fù)用的實現(xiàn)。繼承優(yōu)點1/3/2023111容易進行新的實現(xiàn),因為其大多數(shù)可繼承而來。繼承優(yōu)點12/28破壞了封裝性,因為這會將父類的實現(xiàn)

溫馨提示

  • 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

提交評論