2. O Open Closed Principle (OCP) 開放封閉
3. L Liskov’s Substitution Principle (LSP) 里氏替換原則
4. I Interface Segregation Principle (ISP) 介面隔離
5. D Dependency Inversion Principle (DIP) 依賴倒轉
各原則是相通且相輔相成的。(廢話,各原則當然不可能互相抵觸。)
某原則可能是其他原則的基礎。
因為注重『單一職責』,程式碼才容易維持『開放封閉』。
因為『里氏替換原則』,才能用替換子物件的方式擴充功能(開放封閉)。
因為『介面隔離』,每個物件遵循各自介面,才能『依賴倒轉』。
Single Responsibility Principle
單一職責原則 / 只能有單一原因去更改類別
- There should never be more than one reason for a class to change.
- 每個類別(或者模組)只能有一種原因去改變它。意即每個類別只負責一個職責。
原文由Robert C. Martin在《敏捷軟體開發,原則,模式和實踐》一書提出。
Robert C. Martin把職責定義為「改變的原因」。職責從另一個角度,就是改變的原因。也許從這個角度看,比較容易劃分。
書中範例:
一個用於編輯和列印報表的類別,有兩種原因會改變它,一個是因為報表內容改變,一個是報表格式改變。這兩種原因有本質上的不同,
所以應區分為兩個類。否則會因為改動其中一個原因而影響另一個。
設計類別(模組)時,要思考,之後只能因為一種原因而改變這個類別的內容。
如果你只會因為一種原因改變它,那它自然就只有一種職責。
從這個角度去思考職責劃分,就比較容易了。
範例武器系統:
遊戲的武器系統模組有「強化」「進階」等功能。每個都應該是一個單一模組。
兩個功能對象都是武器,可能輸入的是相同資料。
如果企劃更改「強化」效果,就要改模組。但「強化」跟「進階」是各自獨立的,所以設計成單一模組。
Open Closed Principle
開放封閉原則
- Software entities (classes, modules, functions) should be open for extension but closed for modification.
- 軟體實體(包括類別,模組,函式等)應讓外部能擴展自己的功能,
外部透過繼承等方式,擴充某實體的功能。關鍵字是:擴展。
外部不能修改它原本的功能。關鍵字是:修改。
垂直擴展:
實作上使用介面的方式,定義出開放的部分。繼承者實作介面,然後加讓自己的功能,可達到垂直擴展。
橫向擴展:
新的實體實作相同的介面,裡面提供不同的功能,就能達到橫向擴展。
橫向擴展:
一個實體實作了兩組介面,就能成為兩組繼承鏈的橋樑,達到橫向擴展。
除開放的介面外,其餘一律不跟外界接觸,達到修改封閉。
Lislov's Substitution Principle
里氏替換原則
- Let q(x) be a property provable about objects x of type T. Then q(y) should be true for objects y of type S where S is a subtype of T.
- 物件的父類可被其子類替換,而程式行為並無改變。
因為雙方依賴於抽象層,於是可替換。
Interface Segregation Principle
介面隔離原則
- Clients should not be forced to depend upon interfaces that they don't use.
- The dependency of one class to another one should depend on the smallest possible interface。
- 實作端不應被強迫依賴於它們用不到的介面上。
- 一個類別依賴於另一個,最好只依賴於最少的介面上。
類別依賴於另一類別的介面上,也是越少越好,少到只要能滿組自己需求即可。
『單一職責』告訴我們未來修改的原因只能有一個,因此它不可能有太多功能,意即它只需依賴少少的介面。
介面設計時應區分出來,讓每個類別不碰到不需要的介面。
因為都依賴於抽象層,所以抽象層要劃分的小一點,否則就失去這些原則的功能了。
Dependency Inversion Principle
依賴倒轉原則
- A high level module should not depend on low level modules. Both should depend on abstractions.
- Abstractions should not depend on details. Details should depend on abstractions.
- 高層模組不依賴於低層模組(例如某函式庫),兩者應透過抽象層溝通。例如兩者可透過中間定義的介面來溝通。
- 抽象不依賴於細節(實作),細節依賴於抽象,其實跟上面同樣意思。兩者的原則都是要依賴於抽象(某介面)。
相互之間只依賴於介面,誰也不依賴另一方,雙方可以獨立修改,才能做到其他原則。
才能開放-封閉。各自內部修改,透過介面對外開放。子物件只要遵循相同介面,就能擴充功能。
中文翻譯的不好,讓人看不懂。個人的理解是透過抽象介面解除依賴,理解成『依賴解除』好點。