前言
面向對象有人分為五大原則,分別為單一職責原則、開放封閉原則、依賴倒置原則、接口隔離原則、里氏替換原則。
也有人分為六大原則,分別為單一職責原則、開放封閉原則、依賴倒置原則、接口隔離原則、里氏替換原則、迪米特法則。
現在我們來介紹開放封閉原則,也叫開閉原則
開閉原則
1)概念
官方說法是 軟件實體(模塊、類、函數等)應該可以擴展,但是不可以修改。也就是說軟件對擴展開放,對修改關閉。
需要說明的是,對修改關閉不是說軟件設計不能做修改,只是盡量不要做不必要的修改。怎么才能做到呢?那就是有相應的擴展性。
其實,軟件有相應的擴展性是好處,但是不能說每個地方都有擴展。反而造成了代碼的臃腫。所以這里的擴展與修改關閉是有限制的。
開閉原則,可以說是其他五大原則的實現,也是面向對象設計的終極目標。我們也可以說成開閉原則是其他原則的核心。
說了這些概念性的東西,似懂非懂。我們可以試試從下面的例子來看看是否更加上心。
2)深入理解
開閉原則怎么能更深入的理解呢?還是說說我們身邊的例子吧。
比如我們平常喝水用的一次性紙杯。平常人只是用來裝水。喝完水就扔了。這就是這個紙杯的生命周期。紙杯這一生只完成了它的一個功能:裝水。紙杯此時就很封閉了,沒有什么擴展性。
此時,我看到身邊有一支花苗,我想要拿回家種。但是沒有容器呀? 啊?旁邊不是有一個紙杯嗎,可以用此紙杯來種這朵花苗。
紙杯有了它的另外一個擴展性,就是種花苗。
紙杯不僅有裝水、種花苗的用途,以后還可以有裝小垃圾、沖茶、回收等功能。對於以后這些功能,我們要想到他們的擴張性。
在紙杯只有一個裝水的功能的時候,我們只寫一個紙杯功能類,說紙杯能裝水。但是以后有擴展呢?這一方面我們要預先判斷。預先判斷它以后可能會根據需求的變動而擴展。對於紙杯本來的裝水功能,不能說不能修改,此功能只能在此函數、類中修改。這就是開閉原則的核心。
所以,紙杯在開閉原則所體現的是:盡量少修改,未來可能擴展的模塊、類做好預算的判斷。如果要修改,只能在此函數此類修改,不能牽涉到其他地方。
下面,我們用UML類圖來直觀地說明一下紙杯的設計吧。
當紙杯只有一個功能,裝水時。有一個紙杯操作接口,有一個紙杯操作實現類。
當我們要添加一個功能 種花苗時,我們不也是加一個方法嗎?如下:
當添加N個方法時,不也是在紙杯的操作接口上面添加N個方法嗎?
我們想一想,此時已經背離了我們的開閉原則。因為每添加一個方法,都要在操作類上面做修改。所以,我們按照開閉原則,開做了以下合理的設計:
從上面可以看出,我們把紙杯的操作類,統一寫成一個接口,每個不同的操作繼承此接口來完成各自操作。我們還開到多了一個類,叫客戶端類,其實此類也不難理解。也就是要最終操作紙杯的類。
3)其他例子
開閉原則其實在大話設計模式中說得非常好,讓人通俗易懂。
它舉了一個例子,我覺得說得非常好。是加減乘除法的例子。
開始需求是做一個加法的操作。后來繼續加入減法、乘法、除法。
開始我們想加法以后可能會做一個需求變更:加入其它的算法法則。所以我們要有一個預判性,這個預判性會導致我們項目以后的擴展性,也會導致如果需求發生變更,程序修改的難易程度。
所以,我們要做一個算法法則的操作類,加減乘除法都繼承此操作接口。再加一個算法法則的客戶端類類操作此算法。
我們來上一下大話設計模式中的圖:
4)總結
開閉原則是我們面向對象設計的目標,我們靈活地運用好此目標也不是易事。所以開閉原則要深入的理解,才能做好面向對象的編程,才能做一個好的軟件。
其他鏈接:
此文轉發,請注明出處,謝謝。
可以關注本人的公眾號,多年經驗的原創文章共享給大家。