2018年8月5日 星期日

OOP的五個原則

1. S Single Responsibility Principle (SRP) 單一職責
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.
  • 高層模組不依賴於低層模組(例如某函式庫),兩者應透過抽象層溝通。例如兩者可透過中間定義的介面來溝通。
  • 抽象不依賴於細節(實作),細節依賴於抽象,其實跟上面同樣意思。兩者的原則都是要依賴於抽象(某介面)。

相互之間只依賴於介面,誰也不依賴另一方,雙方可以獨立修改,才能做到其他原則。

才能開放-封閉。各自內部修改,透過介面對外開放。子物件只要遵循相同介面,就能擴充功能。

中文翻譯的不好,讓人看不懂。個人的理解是透過抽象介面解除依賴,理解成『依賴解除』好點。

沒有留言:

張貼留言