當決定鐵人賽的題目是 Design Patterns 時,除了先 Google 看看網路的文章、心得之外,我會去看天瓏書店的網站,尋找該領域的專業書籍,於是乎,我先找尋「Design Patterns: Elements of Reusable Object-Oriented Software」,當然,時間有限的情況下,優先選擇中文版本,在網頁上除了「物件導向設計模式」之外,還另外推薦兩本書,分別是「深入淺出設計模式」與「大話設計模式」。購入這三本書之後,「物件導向設計模式」翻沒幾頁就先暫時擱下,沒有背景知識下閱讀起來不輕鬆。反倒是「深入淺出設計模式」與「大話設計模式」則完全不同,在淺顯易懂的文字帶領下,慢慢領略、欣賞設計模式的美好。
其中,有五個原則這兩本書中不斷被提及,搭配 Google 後才了解到,SOLID,就是這五個原則取第一個字母組合而成,實際閱讀、理解後,覺得這些原則可說是設計模式之所以這樣實作的前提,可以這麼說,遵守 SOLID 原則的不一定有某個模式,而實作某個模式的,則可以看到 SOLID 的身影。
看來得好好了解五個原則。
參考中文 Wiki 資料(連結),提倡者是 Clean Code 的作者 Robert C. Martin。
英文 Wiki 定義(連結):
The single-responsibility principle (SRP) is a computer-programming principle that states that every module, class or function in a computer program should have responsibility over a single part of that program's functionality, and it should encapsulate that part. All of that module, class or function's services should be narrowly aligned with that responsibility.
簡單來說,讓模組、類別或是函式的功能單一化,不要有包山包海的功能。用商學院的概念,可以聯想到「Jobs To Be Done」,人們需要這個產品是因為要完成某件事。同理,當使用模組、類別或是函式時,是因為要完成某個需求才呼叫它們。
英文 Wiki 定義(連結):
In object-oriented programming, the open–closed principle states "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification"; that is, such an entity can allow its behaviour to be extended without modifying its source code.
簡單來說,模組、類別或是函式對於擴充是容易可行的,同時,擴充的時候不會,也不需要更動既有的程式碼。能夠達成此原則的做法是維持低耦合,避免開發新功能時得一併更新舊的程式碼。
英文 Wiki 定義(連結):
Liskov substitution principle (LSP), or Substitutability is a principle in object-oriented programming stating that, in a computer program, if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., an object of type T may be substituted with any object of a subtype S) without altering any of the desirable properties of the program (correctness, task performed, etc.).
簡單來說,關於物件的繼承部分。如果程式的運作一切正常,那具有子代的親代物件可以被取代,程式的運作不會受到影響。用現實物品來講,三菱的轉轉筆,不論使用第一代還是第六代,都可以達到書寫的目的。
英文 Wiki 定義(連結):
In the field of software engineering, the interface-segregation principle (ISP) states that no client should be forced to depend on methods it does not use. ISP splits interfaces that are very large into smaller and more specific ones so that clients will only have to know about the methods that are of interest to them.
簡單來說,避免製造出通用的 Interface,反而是盡可能製造小的 Interface 好滿足特定需求。用現實來說,動物的跑步,不該用一個包含全部的 Interface,反而要設計兩條腿跑步的 Interface、四條腿的、昆蟲的等等。
這段 JavaScript 開發者來說有點陌生,在物件導向語言中,因為大部分只允許單一物件繼承,但偏偏有些方法來自不同物件時,可以使用 Interface 存放將不同類別的共通擁有的方法,且 Interface 允許多重實作,這帶來的好處是提供開發者開發上的彈性。
英文 Wiki 定義(連結):
In object-oriented design, the dependency inversion principle is a specific form of loosely coupling software modules. When following this principle, the conventional dependency relationships established from high-level, policy-setting modules to low-level, dependency modules are reversed, thus rendering high-level modules independent of the low-level module implementation details.
簡單來說,在設計物件的繼承上,盡可能將概念性的內容取出成抽象性的東西(像是 Abstract Class 或 Interface)。在開發上因為將精華的部分萃取出來,後續在實作上、繼承上能盡可能避免高耦合的情況。
這段 JavaScript 開發者來說有點陌生、不好理解,因為 JavaScript 沒有 Abstract Class、Interface,導致後續實作 Patterns 時,JavaScript 將省略這一塊。
對 JavaScript 開發者來說,這五個原則中,SRP 和 OCP 是相對容易遵守的,另外三個則因為語言特色(缺乏虛擬層)導致不太容易遵守。但這沒影響,原則的功用是了解概念後學習如何運用,不需要墨守成規。