官术网_书友最值得收藏!

1.2.6 開閉原則

開閉原則中,“開”是指對擴展開放,“閉”是指對修改關閉。簡單來說,開閉原則就是指:如果你想要修改一個功能,請不要直接進行內部的代碼修改,而是使用擴展的方式進行。如果讀者對此原則感覺模糊,也不必著急,在我們后續項目實戰章節“日志的解析處理”部分,會通過“模板方法模式”進行項目的實戰落地,而模板方法模式就是開閉原則的典型設計模式之一。

按照筆者的習慣,我們依然要以源碼為示例,對開閉原則的應用示例進行說明。開閉原則的源碼應用非常廣泛,我們可以基于上節內容涉及的Spring容器核心refresh()方法中的后置處理器擴展方法postProcessBeanFactory(bean Factory)進行說明,想要實現不同功能的后置處理器,不需要修改Spring本身的代碼(對內修改關閉),只需要子類覆寫postProcessBeanFactory(beanFac tory)方法進行后置處理器的定義即可(對外擴展開放);也可以基于refresh()方法中的onRefresh()方法進行說明,引入SpringBoot內嵌Web容器的源碼實現,對SpringBoot源碼中的ServletWebServerApplicationContext類進行分析,體會Spring對SpringBoot的擴展開放;還可以基于JDK的HashMap源碼為其子類LinkedHashMap提供的afterNodeAccess、afterNodeInsertion、afterNodeRemoval三大擴展方法進行說明,體會HashMap的對內修改關閉,以及對外(LinkedHashMap)開放擴展的設計等。

但是,經過筆者的再三考慮,我想為大家提供更加熱門的、有關并發編程的AQS源碼示例來闡述開閉原則的“對外擴展開放”與“對內修改關閉”。

相信大家對AQS并不陌生,它的全稱是AbstractQueuedSynchronizer,它是位于JDK源碼Java并發包中的一個抽象類,此類基于FIFO(First In - First Out,先進先出)隊列,提供了實現鎖和線程同步的框架,我們開發過程中經常使用到的ReentrantLock就是基于AQS抽象類進行的鎖的實現。

前文提到過模板方法模式是開閉原則的代表性實現,AQS也是基于模板方法模式的設計,我們先來看看AQS中“對外擴展開放”的源碼片段,代碼如下:

我們可以看到,AQS源碼中提供了五個需要擴展的方法,這些方法都是同步鎖最核心的邏輯:加鎖、釋放鎖、是否持有鎖判斷。如此核心的邏輯可以任由子類進行個性化擴展,這就是所謂的“對外開放擴展”。

那么,“對內修改關閉”從何處體現呢?AQS將以上五個方法,嵌入到了統一的代碼模板中,雖然支持子類個性化的擴展核心邏輯,但是整體執行流程是不可以進行修改的,為了說明“對內修改關閉”,我們先來看以下源碼片段。

從以上代碼我們可以清晰地看到,tryAcquire方法的調用時機和tryRelease方法的調用時機,都已經被AQS實現了,AQS對整體的調用邏輯和時機進行了全面的把控,子類無法進行修改,這就是“對內修改關閉”的寫照。

筆者經常把AQS開閉原則的設計比喻成生老病死的自然規律,蕓蕓眾生,從呱呱墜地到歸于塵土,這一自然規律無法修改,這就是“對內修改關閉”;然而,眾生萬象,都有各自的軌跡,不同的選擇造就了不同的命運軌跡,這就是“對外擴展開放”。無論子類如何擴展,終究難免歸于塵土。

我們繼續補充筆者總結的那句話:“單一職責原則以職責為基準劃分類和接口;劃分出來的接口需要最小化,剔除無用接口方法,在接口隔離原則下進行精確的使用;子類對父類的實現需要依據里氏替換原則,在實現所有抽象方法的前提下,可以增加個性化功能,至此子類和父類就創建完成了;當我們使用該類時,要面向接口編程,遵循依賴倒置原則;不同的類或接口之間,要遵循最小知識原則,減少互相的耦合,遵循迪米特法則;如果你的設計需要修改,請盡量提升代碼的擴展性,追求對內修改關閉,對外開放擴展的開閉原則。”

設計模式的原則,固然是無數先輩程序員留給我們最好的財富,我們會認真品味、吸收,融會貫通到實際的開發場景之中。但規則是死的,人是活的,我們依然要以具體的業務流程和需求場景為出發點進行代碼的設計,因地制宜,沒有最優的,只有最合適的。

主站蜘蛛池模板: 红河县| 定远县| 赤壁市| 通州市| 罗甸县| 栖霞市| 塘沽区| 思南县| 徐水县| 隆子县| 盘山县| 嘉祥县| 汉沽区| 玉田县| 富民县| 兰州市| 昌江| 元江| 家居| 巴青县| 通州市| 泾川县| 红原县| 石泉县| 通化县| 抚松县| 邯郸市| 遵义市| 伊川县| 克山县| 余庆县| 吕梁市| 璧山县| 土默特右旗| 漳平市| 晋中市| 甘德县| 广东省| 宣化县| 怀远县| 翁源县|