Java面向物件16種設計原則(總結版)
Java面向物件16種設計原則
一 類的設計原則
1 依賴倒置原則-Dependency Inversion Principle (DIP)
2 里氏替換原則-Liskov Substitution Principle (LSP)
3 介面分隔原則-Interface Segregation Principle (ISP)
4 單一職責原則-Single Responsibility Principle (SRP)
5 開閉原則-The Open-Closed Principle (OCP)
二 包的設計原則
6 重用釋出等價原則-Release ReuseEquivalency Principle (REP)
7 無環依賴原則-The AcyclicDependencies Principle (ADP)
8 穩定依賴原則-The StableDependencies Principle (SDP)
9 穩定抽象等價原則-The StableAbstractions Principle (SAP)
10 共同封閉原則-The CommonClosure Principle (CCP)
11 全部重用原則-The Common Reuse Principle (CRP)
三 擴充套件原則
12 迪米特法則 -Least Knowledge Principle (LKP)
13 黑盒原則- BBP(Black Box Principle)
14 預設抽象原則 -DAP(Default Abstraction Principle)
15 介面設計原則 -IDP(Interface Design Principle)
16 不要構造具體的超類原則 -DCSP(Don't Concrete SupperclassPrinciple)
1. Dependency Inversion Principle (DIP) - 依賴倒置原則
依賴:在程式設計中,如果一個模組a使用或呼叫了另一個模組b,我們稱模組a依賴模組b。 依賴倒置原則的2個重要方針:
為什麼叫做依賴倒置(Dependency Inversion)呢?
問題的提出: Robert C. Martin在原文中給出了“Bad Design”的定義: 問題的解決: 為了解決上述問題,Robert C. Martin提出了OO設計的Dependency Inversion Principle (DIP) 原則。
2. Liskov Substitution Principle (LSP) - 里氏替換原則
|
3. Interface Segregation Principle (ISP) - 介面分隔原則
ISP原則的違反例:
但這樣一來,依賴Door介面的CommonDoor卻不得不實現未使用的alarm()方法。違反了ISP原則。
遵循ISP原則的例:
Adapter設計模式的實現。 在Alarm介面定義alarm方法,在Door介面定義lock,unlock方法。介面之間無繼承關係。CommonDoor實現Door介面, 小結 Interface Segregation Principle (ISP)從對介面的使用上為我們對介面抽象的顆粒度建立了判斷基準:在為系統設計介面的時候,使用多個專門的介面代替單一的胖介面。 |
4. Single Responsibility Principle (SRP) - 單一職責原則
永遠不要讓一個類存在多個改變的理由。換句話說,如果一個類需要改變,改變它的理由永遠只有一個。如果存在多個改變它的理由,就需要重新設計該類。 職責的劃分 既然一個類不能有多個職責,那麼怎麼劃分職責呢? 讓ModemImplementation實現這兩個介面。我們注意到,ModemImplementation又組合了2個職責,這不是我們希望的,但有時這又是必須的。通常由於某些原因,迫使我們不得不繫結多個職責到一個類中,但我們至少可以通過介面的分割來分離應用程式關心的概念。 小結 Single Responsibility Principle (SRP)從職責(改變理由)的側面上為我們對類(介面)的抽象的顆粒度建立了判斷基準:在為系統設計類(介面)的時候應該保證它們的單一職責性。 |
5. The Open-Closed Principle (OCP) - 開閉原則
開閉原則(OCP:Open-Closed Principle)是指在進行面向物件設計(OOD:Object Oriented Design)中,設計類或其他程式單位時,應該遵循: 開閉原則的實現方法 為了滿足開閉原則的 對修改關閉(closed for modification) 原則以及擴充套件開放(open for extension) 原則,應該對軟體系統中的不變的部分加以抽象,在面向物件的設計中, 開閉原則的相對性 軟體系統的構建是一個需要不斷重構的過程,在這個過程中,模組的功能抽象,模組與模組間的關係,都不會從一開始就非常清晰明瞭,所以構建100%滿足開閉原則的軟體系統是相當困難的,這就是開閉原則的相對性。但在設計過程中,通過對模組功能的抽象(介面定義),模組之間的關係的抽象(通過介面呼叫),抽象與實現的分離(面向介面的程式設計)等,可以儘量接近滿足開閉原則。 6. Release Reuse Equivalency Principle (REP) - 重用釋出等價原則
|
7. The Acyclic Dependencies Principle (ADP) - 無環依賴原則
包之間的依賴結構必須是一個直接的無環圖形(DAG)。也就是說,在依賴結構中不允許出現環(迴圈依賴)。換成另一個說法是: 包間依賴不能是一個環狀形式。包間關係方面(耦合性)的原則 包的依賴
包的迴圈依賴 圖2:包的迴圈依賴 包的非迴圈依賴原則 包是一個比較合適的釋出粒度,當修改了包中的程式碼(類,模組等)併發布新的版本時,我們需要把該包以及它所依賴的其它包一起釋出。釋出之後,還需要驗證系統是否能在新發布的版本下正常運作。 迴圈依賴的打破方法 如果包的依賴形成了環狀結構,怎麼樣打破這種迴圈依賴呢? 方法一:建立新的包
方法二:DIP與ISP設計原則
小結 無環依賴原則(ADP)為我們解決包之間的關係耦合問題。在設計包結構時,不能有迴圈依賴。 |
8. The Stable Dependencies Principle (SDP) - 穩定依賴原則
一個設計中的包之間的依賴應該朝著穩定的方向進行。一個包只應該依賴那些比自己更穩定的包。換成另一個說法是: 朝著穩定的方向進行依賴。包之間的關係方面(耦合性)的原則。 包的依賴 如果一個包A 中的類引用了包B中的類,我們稱包A依賴包B。 圖1(包A依賴包B) 包的穩定依賴原則 包應該依賴比自己更穩定的包。因為如果依賴一個不穩定的包,那麼當這個不穩定的包發生變化時,本身穩定的包也不得不發生變化,變得不穩定了。 圖1:穩定的包X
包的穩定性的判斷原則 可以通過下面的方法來判斷一個包的穩定係數: 穩定依賴原則(SDP)為我們解決包之間的關係耦合問題。在設計包結構時,包應該只依賴比自己更穩定的包。 |
9. The Stable AbstractionsPrinciple (SAP) - 穩定抽象等價原則
最穩定的包應該是最抽象的包。不穩定的包應該是具體的包。包的抽象程度跟它的穩定性成正比。穩定的包應該是抽象的包。 包的穩定抽象等價原則
穩定的包的構成 理想的體系結構應該是: 圖1:遵循穩定依賴原則(SDP)的理想的體系結構 小結 穩定抽象等價原則(SAP)為我們解決包之間的關係耦合問題。在設計包結構時,穩定的包應該是抽象的(由抽象類或介面構成),不穩定的包應該是具體的(由具體的實現類構成)。 |
10. The Common ClosurePrinciple (CCP) - 共同封閉原則
小結 共同封閉原則(CCP)從軟體功能的角度上為我們規範了包設計的一個原則:在設計包時,相互之間緊密關聯的類應該放在同一包裡。 |
11. The Common Reuse Principle (CRP) - 全部重用原則
包的所有類被一起重用。如果你重用了其中的一個類,就重用全部。換成另一個比較淺顯易懂的說法:沒有被一起重用的類不應該被組合在一起。CRP原則幫助我們決定哪些類應該被放到同一個包裡。包的內部關係方面(聚合性)的原則 全部重用原則(CRP)從使用者的角度上為我們規範了包設計的一個原則:在設計包時,相互之間沒有緊密關聯的類不應該放在同一包裡。 12. Least Knowledge Principle (LKP) -迪米特法則 迪米特法則(Law of Demeter,LoD)也稱為最少知識原則(Least Knowledge Principle,LKP)。 一個物件應該對其他物件有最少的瞭解。通俗地講,一個類應該對自己需要耦合或呼叫的類知道得最少,你(被耦合或呼叫的類)的內部是如何複雜都和我沒關係,那是你的事情,我就知道你提供的public方法,我就呼叫這麼多,其他的一概不關心。 含義:
朋友類的定義是這樣的:出現在成員變數、方法的輸入輸出引數中的類稱為成員朋友類,而出現在方法體內部的類不屬於朋友類。下面的程式碼在方法體內部依賴了其他類,這嚴重違反迪米特法則
方法是類的一個行為,類竟然不知道自己的行為與其他類產生了依賴關係,這是不允許的。 正確的做法是:
注意:一個類只和朋友交流,不與陌生類交流,不要出現getA().getB().getC().getD()這種情況(在一種極端情況下允許出現這種訪問,即每一個點號後面的返回型別都相同),類與類之間的關係是建立在類間的,而不是方法間,因此一個方法儘量不引入一個類中不存在的物件,當然,JDK API提供的類除外。
一個類公開的public屬性或方法越多,修改時涉及的面也就越大,變更引起的風險擴散也就越大。因此,為了保持朋友類間的距離,在設計時需要反覆衡量:是否還可以再減少public方法和屬性,是否可以修改為private、package-private(包型別,在類、方法、變數前不加訪問許可權,則預設為包型別)、protected等訪問許可權,是否可以加上final關鍵字等。 注意:迪米特法則要求類“羞澀”一點,儘量不要對外公佈太多的public方法和非靜態的public變數,儘量內斂,多使用private、package-private、protected等訪問許可權。
如果一個方法放在本類中,既不增加類間關係,也對本類不產生負面影響,就放置在本類中。
最後,迪米特法則的核心觀念就是類間解耦,弱耦合,只有弱耦合了以後,類的複用率才可以提高。 |
Principle –縱覽
----類原則 ----
1.單一職責原則 -Single Responsibility Principle(SRP)
就一個類而言,應該僅有一個引起它變化的原因。
(職責即為“變化的原因”。)
2.開放-封閉原則 - OpenClose Principle(OCP)
軟體實體(類、模組、函式等)應該是可以擴充套件的,但是不可修改。
(對於擴充套件是開放的,對於更改是封閉的.
關鍵是抽象.將一個功能的通用部分和實現細節部分清晰的分離開來.
開發人員應該僅僅對程式中呈現出頻繁變化的那些部分作出抽象.
拒絕不成熟的抽象和抽象本身一樣重要. )
3.里氏替換原則 -Liskov Substitution Principle(LSP)
子型別(subclass)必須能夠替換掉它們的基型別(superclass)。
4.依賴倒置原則(IoCP) 或 依賴注入原則 -Dependence Inversion Principle(DIP)
抽象不應該依賴於細節。細節應該依賴於抽象。
(Hollywood原則: "Don't call us, we'll call you".
程式中所有的依賴關係都應該終止於抽象類和介面。
針對介面而非實現程式設計。
任何變數都不應該持有一個指向具體類的指標或引用。
任何類都不應該從具體類派生。
任何方法都不應該覆寫他的任何基類中的已經實現了的方法。)
5.介面隔離原則(ISP)
不應該強迫客戶依賴於它們不用的方法。
介面屬於客戶,不屬於它所在的類層次結構。
(多個面向特定使用者的介面勝於一個通用介面。)
----包內聚原則 ----
6.重用釋出等價原則(REP)
重用的粒度就是釋出的粒度。
7.共同封閉原則(CCP)
包中的所有類對於同一類性質的變化應該是共同封閉的。
一個變化若對一個包產生影響,
則將對該包中的所有類產生影響,
而對於其他的包不造成任何影響。
8.共同重用原則(CRP)
一個包中的所有類應該是共同重用的。
如果重用了包中的一個類,
那麼就要重用包中的所有類。
(相互之間沒有緊密聯絡的類不應該在同一個包中。)
----包耦合原則
9.無環依賴原則(ADP)
在包的依賴關係圖中不允許存在環。
10.穩定依賴原則(SDP)
朝著穩定的方向進行依賴。
應該把封裝系統高層設計的軟體(比如抽象類)放進穩定的包中,
不穩定的包中應該只包含那些很可能會改變的軟體(比如具體類)。
11.穩定抽象原則(SAP)
包的抽象程度應該和其穩定程度一致。
(一個穩定的包應該也是抽象的,一個不穩定的包應該是抽象的. )
----其它擴充套件原則----
12.BBP(Black Box Principle)黑盒原則
多用類的聚合,少用類的繼承。
13.DAP(Default Abstraction Principle)預設抽象原則
在介面和實現介面的類之間引入一個抽象類,這個類實現了介面的大部分操作.
14.IDP(Interface Design Principle)介面設計原則
規劃一個介面而不是實現一個介面。
15.DCSP(Don't Concrete Supperclass Principle)不要構造具體的超類原則
避免維護具體的超類。
16.迪米特法則
一個類只依賴其觸手可得的類。