開閉原則(Open-Closed Principle,OCP)
1 什么是開閉原則
開閉原則是面向?qū)ο笤O(shè)計中“可復(fù)用設(shè)計”的基石,是面向?qū)ο笤O(shè)計中最重要的原則之一,其它很多的設(shè)計原則都是實(shí)現(xiàn)開閉原則的一種手段。
1988年,Bertrand Meyer在他的著作《Object Oriented Software Construction》中提出了開閉原則,它的原文是這樣:“Software entities should be open for extension,but closed for modification”。翻譯過來就是:“軟件實(shí)體應(yīng)當(dāng)對擴(kuò)展開放,對修改關(guān)閉”。這句話說得略微有點(diǎn)專業(yè),我們把它講得更通俗一點(diǎn),也就是:軟件系統(tǒng)中包含的各種組件,例如模塊(Modules)、類(Classes)以及功能(Functions)等等,應(yīng)該在不修改現(xiàn)有代碼的基礎(chǔ)上,引入新功能。開閉原則中“開”,是指對于組件功能的擴(kuò)展是開放的,是允許對其進(jìn)行功能擴(kuò)展的;開閉原則中“閉”,是指對于原有代碼的修改是封閉的,即不應(yīng)該修改原有的代碼。
2 如何實(shí)現(xiàn)開閉原則
實(shí)現(xiàn)開閉原則的關(guān)鍵就在于“抽象”。把系統(tǒng)的所有可能的行為抽象成一個抽象底層,這個抽象底層規(guī)定出所有的具體實(shí)現(xiàn)必須提供的方法的特征。作為系統(tǒng)設(shè)計的抽象層,要預(yù)見所有可能的擴(kuò)展,從而使得在任何擴(kuò)展情況下,系統(tǒng)的抽象底層不需修改;同時,由于可以從抽象底層導(dǎo)出一個或多個新的具體實(shí)現(xiàn),可以改變系統(tǒng)的行為,因此系統(tǒng)設(shè)計對擴(kuò)展是開放的。
我們在軟件開發(fā)的過程中,一直都是提倡需求導(dǎo)向的。這就要求我們在設(shè)計的時候,要非常清楚地了解用戶需求,判斷需求中包含的可能的變化,從而明確在什么情況下使用開閉原則。
關(guān)于系統(tǒng)可變的部分,還有一個更具體的對可變性封裝原則(Principle of Encapsulation of Variation, EVP),它從軟件工程實(shí)現(xiàn)的角度對開閉原則進(jìn)行了進(jìn)一步的解釋。EVP要求在做系統(tǒng)設(shè)計的時候,對系統(tǒng)所有可能發(fā)生變化的部分進(jìn)行評估和分類,每一個可變的因素都單獨(dú)進(jìn)行封裝。
我們在實(shí)際開發(fā)過程的設(shè)計開始階段,就要羅列出來系統(tǒng)所有可能的行為,并把這些行為加入到抽象底層,根本就是不可能的,這么去做也是不經(jīng)濟(jì)的,費(fèi)時費(fèi)力。另外,在設(shè)計開始階段,對所有的可變因素進(jìn)行預(yù)計和封裝也不太現(xiàn)實(shí),也是很難做得到。所以,開閉原則描繪的愿景只是一種理想情況或是極端狀態(tài),現(xiàn)實(shí)世界中是很難被完全實(shí)現(xiàn)的。我們只能在某些組件,在某種程度上符合開閉原則的要求。
通過以上的分析,對于開閉原則,我們可以得出這樣的結(jié)論:雖然我們不可能做到的封閉,但是在系統(tǒng)設(shè)計的時候,我們還是要盡量做到這一點(diǎn)。
對于軟件系統(tǒng)的功能擴(kuò)展,我們可以通過繼承、重載或者委托等手段實(shí)現(xiàn)。以接口為例,它對修改就是是封閉的,而對具體的實(shí)現(xiàn)是開放的,我們可以根據(jù)實(shí)際的需要提供不同的實(shí)現(xiàn),所以接口是符合開閉原則的。
3 開閉原則能夠帶來什么好處
如果一個軟件系統(tǒng)符合開閉原則的,那么從軟件工程的角度來看,它至少具有這樣的好處:
可復(fù)用性好。
我們可以在軟件完成以后,仍然可以對軟件進(jìn)行擴(kuò)展,加入新的功能,非常靈活。因此,這個軟件系統(tǒng)就可以通過不斷地增加新的組件,來滿足不斷變化的需求。
可維護(hù)性好。
由于對于已有的軟件系統(tǒng)的組件,特別是它的抽象底層不去修改,因此,我們不用擔(dān)心軟件系統(tǒng)中原有組件的穩(wěn)定性,這就使變化中的軟件系統(tǒng)有一定的穩(wěn)定性和延續(xù)性。
4 開閉原則與其它原則的關(guān)系
開閉原則具有理想主義的色彩,它是面向?qū)ο笤O(shè)計的終極目標(biāo)。因此,針對開閉原則的實(shí)現(xiàn)方法,一直都有面向?qū)ο笤O(shè)計的大師費(fèi)盡心機(jī),研究開閉原則的實(shí)現(xiàn)方式。后面要提到的里氏代換原則(LSP)、依賴倒轉(zhuǎn)原則(DIP)、接口隔離原則(ISP)以及抽象類(Abstract Class)、接口(Interace)等等,都可以看作是開閉原則的實(shí)現(xiàn)方法。
1 什么是開閉原則
開閉原則是面向?qū)ο笤O(shè)計中“可復(fù)用設(shè)計”的基石,是面向?qū)ο笤O(shè)計中最重要的原則之一,其它很多的設(shè)計原則都是實(shí)現(xiàn)開閉原則的一種手段。
1988年,Bertrand Meyer在他的著作《Object Oriented Software Construction》中提出了開閉原則,它的原文是這樣:“Software entities should be open for extension,but closed for modification”。翻譯過來就是:“軟件實(shí)體應(yīng)當(dāng)對擴(kuò)展開放,對修改關(guān)閉”。這句話說得略微有點(diǎn)專業(yè),我們把它講得更通俗一點(diǎn),也就是:軟件系統(tǒng)中包含的各種組件,例如模塊(Modules)、類(Classes)以及功能(Functions)等等,應(yīng)該在不修改現(xiàn)有代碼的基礎(chǔ)上,引入新功能。開閉原則中“開”,是指對于組件功能的擴(kuò)展是開放的,是允許對其進(jìn)行功能擴(kuò)展的;開閉原則中“閉”,是指對于原有代碼的修改是封閉的,即不應(yīng)該修改原有的代碼。
2 如何實(shí)現(xiàn)開閉原則
實(shí)現(xiàn)開閉原則的關(guān)鍵就在于“抽象”。把系統(tǒng)的所有可能的行為抽象成一個抽象底層,這個抽象底層規(guī)定出所有的具體實(shí)現(xiàn)必須提供的方法的特征。作為系統(tǒng)設(shè)計的抽象層,要預(yù)見所有可能的擴(kuò)展,從而使得在任何擴(kuò)展情況下,系統(tǒng)的抽象底層不需修改;同時,由于可以從抽象底層導(dǎo)出一個或多個新的具體實(shí)現(xiàn),可以改變系統(tǒng)的行為,因此系統(tǒng)設(shè)計對擴(kuò)展是開放的。
我們在軟件開發(fā)的過程中,一直都是提倡需求導(dǎo)向的。這就要求我們在設(shè)計的時候,要非常清楚地了解用戶需求,判斷需求中包含的可能的變化,從而明確在什么情況下使用開閉原則。
關(guān)于系統(tǒng)可變的部分,還有一個更具體的對可變性封裝原則(Principle of Encapsulation of Variation, EVP),它從軟件工程實(shí)現(xiàn)的角度對開閉原則進(jìn)行了進(jìn)一步的解釋。EVP要求在做系統(tǒng)設(shè)計的時候,對系統(tǒng)所有可能發(fā)生變化的部分進(jìn)行評估和分類,每一個可變的因素都單獨(dú)進(jìn)行封裝。
我們在實(shí)際開發(fā)過程的設(shè)計開始階段,就要羅列出來系統(tǒng)所有可能的行為,并把這些行為加入到抽象底層,根本就是不可能的,這么去做也是不經(jīng)濟(jì)的,費(fèi)時費(fèi)力。另外,在設(shè)計開始階段,對所有的可變因素進(jìn)行預(yù)計和封裝也不太現(xiàn)實(shí),也是很難做得到。所以,開閉原則描繪的愿景只是一種理想情況或是極端狀態(tài),現(xiàn)實(shí)世界中是很難被完全實(shí)現(xiàn)的。我們只能在某些組件,在某種程度上符合開閉原則的要求。
通過以上的分析,對于開閉原則,我們可以得出這樣的結(jié)論:雖然我們不可能做到的封閉,但是在系統(tǒng)設(shè)計的時候,我們還是要盡量做到這一點(diǎn)。
對于軟件系統(tǒng)的功能擴(kuò)展,我們可以通過繼承、重載或者委托等手段實(shí)現(xiàn)。以接口為例,它對修改就是是封閉的,而對具體的實(shí)現(xiàn)是開放的,我們可以根據(jù)實(shí)際的需要提供不同的實(shí)現(xiàn),所以接口是符合開閉原則的。
3 開閉原則能夠帶來什么好處
如果一個軟件系統(tǒng)符合開閉原則的,那么從軟件工程的角度來看,它至少具有這樣的好處:
可復(fù)用性好。
我們可以在軟件完成以后,仍然可以對軟件進(jìn)行擴(kuò)展,加入新的功能,非常靈活。因此,這個軟件系統(tǒng)就可以通過不斷地增加新的組件,來滿足不斷變化的需求。
可維護(hù)性好。
由于對于已有的軟件系統(tǒng)的組件,特別是它的抽象底層不去修改,因此,我們不用擔(dān)心軟件系統(tǒng)中原有組件的穩(wěn)定性,這就使變化中的軟件系統(tǒng)有一定的穩(wěn)定性和延續(xù)性。
4 開閉原則與其它原則的關(guān)系
開閉原則具有理想主義的色彩,它是面向?qū)ο笤O(shè)計的終極目標(biāo)。因此,針對開閉原則的實(shí)現(xiàn)方法,一直都有面向?qū)ο笤O(shè)計的大師費(fèi)盡心機(jī),研究開閉原則的實(shí)現(xiàn)方式。后面要提到的里氏代換原則(LSP)、依賴倒轉(zhuǎn)原則(DIP)、接口隔離原則(ISP)以及抽象類(Abstract Class)、接口(Interace)等等,都可以看作是開閉原則的實(shí)現(xiàn)方法。