開閉原則認為:設計良好的計算機軟件應該易于擴展敷硅,同時抗拒修改愉阎。換句話說力奋,一個設計良好的計算機系統(tǒng)應該在不需要修改的前提下就可以輕易被擴展。這就要處理好組件之間景殷、類之間的依賴關系。
假設我們要設計一個Web頁面上展示財務數據的系統(tǒng)咐旧,過了不久之后該系統(tǒng)的所有者又要求同樣的數據需要形成一個報表能用打印機打印。顯然我們需要增加一些代碼來完成這個要求铣墨,但是這里更需要關注的是办绝,滿足新的需求需要更改多少舊代碼。
一個號的軟件架構設計師會努力將舊代碼的修改需求量降至最小孕蝉,甚至為0。如何實現呢降淮?
- 將滿足不同需求的代碼分組(SRP)
- 調整依賴這些分組之間的依賴關系(DIP)
利用SRP,可以按下圖展示的方式處理數據流骤肛。即先用一段分析程序處理原始的財務數據窍蓝,以形成報表的數據結構,最后再用兩個不同的報表生成器來產生報表吓笙。
接下來面睛,需要調整源代碼之間的依賴關系絮蒿,創(chuàng)建抽象來隔離以后發(fā)生的同類變化土涝。在具體實現上幌墓,我們會將整個程序進程劃分成一系列的類冀泻,然后再將這些類分隔成不同的組件蜡饵。下圖中分成了Controller,Interactor溯祸,Database,Presenter和View。其中<DS>表示數據結構焦辅,<I>代表接口,開放箭頭只帶的是使用關系氨鹏,閉合箭頭指代的是實現與繼承關系。類A指向類B的箭頭意味著A的源代碼中涉及了B跟继,但是B的源代碼中并不涉及A。圖中FinancialDataMapper在實現接口時需要知道FinancialDataGateway的實現舔糖,而FinancialDataGateway則完全不必要知道FinancialDataMapper的存在。圖中所有組件之間的關系都是單向依賴的金吗,箭頭都指向那些我們不經常更改的組件趣竣。
我們不想讓Presenter上的修改影響到Controller,也不想讓View上的修改影響到Presenter卫袒。最關鍵的是不想讓任何修改影響到Interactor。整體來看Interactor是整個系統(tǒng)的核心組件单匣,負責程序的核心邏輯,其他組件只是這個邏輯的輔助邏輯户秤。局部來看,Controller是Presenter和View的核心組件鸡号。
如果現在需要再有某種形式的輸出的話,只需要繼承或者實現FinancialReportPresenter接口擴展就行了府蔗,不需要修改其他的位置莉兰。其中修改數據的存儲的修改糖荒,其他的位置也不需要改變,只需要繼承或者實現FinancialDataMapper就行了捶朵。
總結OCP是我們進行系統(tǒng)結構設計的主導原則狂男,主要目標是讓系統(tǒng)易于擴展,同時限制其每次被修改所影響的范圍岖食。實現方式是通過劃分一系列組件,并且將這些組件間的依賴關系按層次結構進行組織泡垃,似的高階組件不會因低階組件被修改而受到影響。無論組件多么封閉忠寻,都有一些無法封閉的變化,必須要預測那些可能變化的部分做抽象隔離來處理未來的變化奕剃。然而不成熟的抽象捐腿,會造成類的繁多。