標簽(空格分隔): 設計模式
1、單一職責原則(SRP:Single responsibility principle)
核心:每一個類應該專注于做一件事情。
這樣做可以降低類的復雜度,一個類只負責一項職責,其邏輯肯定要比負責多項職責簡單的多;提高類的可讀性,提高系統的可維護性;變更引起的風險降低,變更是必然的,如果單一職責原則遵守的好,當修改一個功能時,可以顯著降低對其他功能的影響。需要說明的一點是單一職責原則不只是面向對象編程思想所特有的,只要是模塊化的程序設計,都適用單一職責原則。
從大局上看Android中的Paint和Canvas等類都遵守單一職責原則,Paint和Canvas各司其職。
2、里氏替換原則(LSP:Liskov Substitution Principle)
核心:在任何父類出現的地方都可以用它的子類來替代(子類應當可以替換父類并出現在父類能夠出現的任何地方)
四層含義:
(1)子類必須完全實現父類的方法。在類中調用其他類是務必要使用父類或接口,如果不能使用父類或接口,則說明類的設計已經違背了LSP原則。
(2)子類可以有自己的個性。子類當然可以有自己的行為和外觀了,也就是方法和屬性
(3)覆蓋或實現父類的方法時輸入參數可以被放大。即子類可以重載父類的方法,但輸入參數應比父類方法中的大,這樣在子類代替父類的時候,調用的仍然是父類的方法。即以子類中方法的前置條件必須與超類中被覆蓋的方法的前置條件相同或者更寬松。
(4)覆蓋或實現父類的方法時輸出結果可以被縮小。
3、依賴倒置原則(DIP:Dependence Inversion Principle)
核心:要依賴于抽象,不要依賴于具體的實現 三層含義:
(1)高層模塊不應該依賴低層模塊,兩者都應該依賴其抽象(抽象類或接口);
(2)抽象不應該依賴細節(具體實現);
(3)細節(具體實現)應該依賴抽象。
三種實現方式:
1、通過構造函數傳遞依賴對象 ;
2、通過setter方法傳遞依賴對象 ;
3、接口聲明實現依賴對象 在Java中的表現:
(1)模塊間的依賴是通過抽象發生,實現類之間不發生直接的依賴關系,其依賴關系是通過接口或抽象類產生的;
(2)接口或抽象類不依賴于實現類;
(3)實現類依賴接口或抽象類。
4、接口分離原則(ISP:Interface Segregation Principle)
核心思想:不應該強迫客戶程序依賴他們不需要使用的方法。接口分離原則的意思就是:一個接口不需要提供太多的行為,一個接口應該只提供一種對外的功能,不應該把所有的操作都封裝到一個接口當中。
接口隔離原則的定義:
第一種定義:客戶端不應該依賴它不需用的接口。
第二種定義:一個類對另外一個類的依賴性應當是建立在最小的接口上的。 接口分以下兩種: 對象接口(Object Interface)Java中聲明的一個類,通過new關鍵字產生的一個實例,對一個類型事物的描述,也是一種接口。 類接口(Class Interface) 通過關鍵字Interface定義的接口。
分離接口的兩種實現方法:
(1) 使用委托分離接口。(Separation through Delegation)就把請求委托給別的接口的實現類來完成需要的職責,就是適配器模式(Adapter)。
(2) 使用多重繼承分離接口。(Separation through Multiple Inheritance。)該方法通過實現多個接口來完成需要的職責。
兩種方式各有優缺點,通常我們應該先考慮后一個方案,如果涉及到類型轉換時則選擇前一個方案。
5、開閉原則(OCP:Open Closed Principle)
核心思想:對擴展開放,對修改關閉。即在設計一個模塊的時候,應當使這個模塊可以在不被修改的前提下被擴展。 根據開閉原則,在設計一個軟件系統模塊(類,方法)的時候,應該可以在不修改原有的模塊(修改關閉)的基礎上,能擴展其功能(擴展開放)。
擴展開放:某模塊的功能是可擴展的,則該模塊是擴展開放的。軟件系統的功能上的可擴展性要求模塊是擴展開放的。
修改關閉:某模塊被其他模塊調用,如果該模塊的源代碼不允許修改,則該模塊修改關閉的。軟件系統的功能上的穩定性,持續性要求是修改關閉的。
開閉原則的實現方法 為了滿足開閉原則的對修改關閉(closed for modification)原則以及擴展開放(open for extension)原則,應該對軟件系統中的不變的部分加以抽象。
在面向對象的設計中:
(1)可以把這些不變的部分加以抽象成不變的接口,這些不變的接口可以應對未來的擴展;
(2)接口的最小功能設計原則。根據這個原則,原有的接口要么可以應對未來的擴展;
(3)不足的部分可以通過定義新的接口來實現;
(4)模塊之間的調用通過抽象接口進行,這樣即使實現層發生變化,也無需修改調用方的代碼。 接口可以被復用,但接口的實現卻不一定能被復用。接口是穩定的,關閉的,但接口的實現是可變的,開放的。可以通過對接口的不同實現以及類的繼承行為等為系統增加新的或改變系統原來的功能,實現軟件系統的柔軟擴展。
簡單地說,軟件系統是否有良好的接口(抽象)設計是判斷軟件系統是否滿足開閉原則的一種重要的判斷基準。現在多把開閉原則等同于面向接口的軟件設計。
開閉原則的相對性:
軟件系統的構建是一個需要不斷重構的過程,在這個過程中,模塊的功能抽象,模塊與模塊間的關系,都不會從一開始就非常清晰明了,所以構建100%滿足開閉原則的軟件系統是相當困難的,這就是開閉原則的相對性。但在設計過程中,通過對模塊功能的抽象(接口定義),模塊之間的關系的抽象(通過接口調用),抽象與實現的分離(面向接口的程序設計)等,可以盡量接近滿足開閉原則。
6、迪米特法則(LOD:Law of Demeter)又叫作:最少知識原則(Least Knowledge Principle 簡寫LKP)
核心思想:一個對象應當對其他對象有盡可能少的了解,不和陌生人說話。(類間解耦,低耦合)意思就是降低各個對象之間的耦合,提高系統的可維護性;在模塊之間只通過接口來通信,而不理會模塊的內部工作原理,可以使各個模塊的耦合成都降到最低,促進軟件的復用。 在將迪米特法則運用到系統的設計中時,應注意的幾點:
(1)在類的劃分上,應該創建有弱耦合的類;
(2) 在類的結構設計上,每一個類都應當盡量降低成員的訪問權限;
(3)在類的設計上,只要有可能,一個類應當設計成不變類;
(4) 在對其他類的引用上,一個對象對其它對象的引用應當降到最低;
(5) 盡量降低類的訪問權限;
(6)謹慎使用序列化功能;
(7)不要暴露類成員,而應該提供相應的訪問器(屬性)
優點:
(1)迪米特法則的初衷在于降低類之間的耦合。由于每個類盡量減少對其他類的依賴,因此,很容易使得系統的功能模塊功能獨立,相互之間不存在(或很少有)依賴關系。
(2)遵循迪米特法則會使一個系統的局部設計簡化,因為每一個局部都不會和遠距離的對象有直接關聯。
缺點:
(1)會在系統里造出大量的小方法,散落在系統的各個角落。這些方法僅僅是傳遞間接的調用,因此與系統的商務邏輯無關,當設計師試圖從一張類圖看出總體的框架時,這些小的方法會造成迷惑和困擾。 (2)會造成系統的不同模塊之間的通信效率降低,也會使系統的不同模塊之間不容易協調。
設計模式中的應用:
(1)門面模式(Facade Pattern)
(2)中介模式(Mediator Pattern)
7、合成聚合復用原則 (CRP:Composite Reuse Principle) 別合成復用原則(Composition/Aggregate Reuse Principle, CARP)
核心思想:盡量使用對象組合,而不是繼承來達到復用的目的。該原則就是在一個新的對象里面使用一些已有的對象,使之成為新對象的一部分:新的對象通過向這些對象的委派達到復用已有功能的目的。
術語:
(1)聚合(Aggregation):聚合用來表示“擁有”關系或者整體與部分的關系;
(2)合成(Composition):合成則用來表示一種強得多的“擁有”關系。在一個合成關系里面,部分和整體的生命周期是一樣的。
復用的種類:
(1)繼承
優點: 新的實現較為容易,因為基類的大部分功能可以通過繼承關系自動進入派生類; 修改或擴展繼承而來的實現較為容易。
缺點: 繼承復用破壞包裝,因為繼承將基類的實現細節暴露給派生類,這種復用也稱為白箱復用; 如果基類的實現發生改變,那么派生類的實現也不得不發生改變;
從基類繼承而來的實現是靜態的,不可能在運行時發生改變,不夠靈活。
(2)合成聚合
優點: 新對象存取成分對象的唯一方法是通過成分對象的接口; 這種復用是黑箱復用,因為成分對象的內部細節是新對象所看不見的; 這種復用支持包裝; 這種復用所需的依賴較少; 每一個新的類可以將焦點集中在一個任務上; 這種復用可以在運行時動態進行,新對象可以使用合成/聚合關系將新的責任委派到合適的對象。
缺點: 通過這種方式復用建造的系統會有較多的對象需要管理。 在復用時應優先考慮使用合成聚合而不是繼承,而判定的判斷為以下四個Coad條件:
(1) 派生類是基類的一個特殊種類,而不是基類的一個角色,即要分清"Has-A"和"Is-A"的區別;
(2) 永遠不會出現需要將派生類換成另一個類的派生類的情況;
(3) 派生類具有擴展基類的責任,而不是具有置換或者注銷掉基類的責任;
(4) 只有在分類學角度有意義時,才可以使用繼承。