SOLID 之 開關原則(Open-close principle)
原文定義是這樣子的:
Software entities (class, modules, functions, etc.) should be open for extension, but closed for modification.
直接翻成中文大概會是:「軟體實體應該對擴展開放,對修改關閉」。這到底在說什麼呀?
說明前,先來看個小範例:
|
這是一個簡單從 API 下載 XML 並解析的小 class。某天 API 單位說要開新 API 改使用 JSON 作回傳格式,但還在測試階段,可以先行測試,下個禮拜將會上線。
請問,這時大家會如何修改這個程式呢?
太簡單了,相信大部分的人應該會想要把解析 XML 的程式改掉,如下:
|
改好測好後,繼續開心的開發其他功能。過了一個禮拜,API 團隊突然說有重大 issue 無法如期上線,可是其他功能要依續上線,不應該因為 API 延期而延期,該怎麼辦呢?
最保險的方法當然是接 XML,因為那是舊有還在線上維運的 API。可是瑞凡,程式都被刪光光,回不去了。
當然版控或是備份還原都能解決,不過我們也可以從設計上解決--重構成新舊規格都可以用的程式!
我們先使用 if
快速實作試看看:
|
如果還記得單一職責原則的話,會發現它有濃濃的壞味道--XML 處理是一種職責、JSON 處理應該是另一種職責。
因為它們都是在解析 $content
因此我們可以抽出一個抽象方法 parse
:
|
截至目前為止,我們使用了樣版方法模式(Template Method Pattern),把解析資料抽離出另一個 class 實作,它同時也符合了單一職責原則。
現在,我們來回想一下需求:「新 API 改使用 JSON 作回傳格式」,可以怎麼實作呢?相信大家會換另一種方法:「寫新的JsonResource
class 繼承 DataResource
,再把使用的地方改成新 class 就好,這太簡單了!」
class JsonResource extends DataResource |
同時也回想一下今天的主題:「軟體實體應該對擴展開放,對修改關閉」
- 對擴展開放:新功能是用寫新的程式碼擴展出來的。
- 對修改關閉:新功能不用修改現有程式碼。
相信這樣大家對開關原則應該有更深的了解了。
優點
最大的好處正是降低修改風險。思考一下,前面的修改,是修改既有程式碼,因此有可能破壞原有功能;後面重構後的修改,只有新增程式碼,舊有程式因為沒修改,所以理論上問題當然會比較少。
潛在問題
擴展的情境並不一定在設計階段就會發現,常常要到了需求調整才會知道,像上面的範例正是如此,誰會知道 API 團隊突然要改 JSON 呢?但我們還是有辦法面對改變的--透過重構讓設計可以更符合需求。