開閉原則是面向對象的可復用設計的第一塊基石焰枢,它是最重要的面向對象設計原則。開閉原則由Bertrand Meyer于1988年提出戈抄,其定義如下:
開閉原則(Open-Closed Principle, OCP):一個軟件實體應當對擴展開放,對修改關閉。即軟件實體應盡量在不修改原有代碼的情況下進行擴展茶袒。
在開閉原則的定義中,軟件實體可以指一個軟件模塊凉馆、一個由多個類組成的局部結構或一個獨立的類薪寓。
任何軟件都需要面臨一個很重要的問題,即它們的需求會隨時間的推移而發(fā)生變化澜共。當軟件系統(tǒng)需要面對新的需求時预愤,我們應該盡量保證系統(tǒng)的設計框架是穩(wěn)定的。如果一個軟件設計符合開閉原則咳胃,那么可以非常方便地對系統(tǒng)進行擴展植康,而且在擴展時無須修改現(xiàn)有代碼,使得軟件系統(tǒng)在擁有適應性和靈活性的同時具備較好的穩(wěn)定性和延續(xù)性展懈。隨著軟件規(guī)模越來越大销睁,軟件壽命越來越長,軟件維護成本越來越高存崖,設計滿足開閉原則的軟件系統(tǒng)也變得越來越重要冻记。
為了滿足開閉原則,需要對系統(tǒng)進行抽象化設計来惧,抽象化是開閉原則的關鍵冗栗。在Java、C#等編程語言中供搀,可以為系統(tǒng)定義一個相對穩(wěn)定的抽象層隅居,而將不同的實現(xiàn)行為移至具體的實現(xiàn)層中完成。在很多面向對象編程語言中都提供了接口葛虐、抽象類等機制胎源,可以通過它們定義系統(tǒng)的抽象層,再通過具體類來進行擴展屿脐。如果需要修改系統(tǒng)的行為涕蚤,無須對抽象層進行任何改動宪卿,只需要增加新的具體類來實現(xiàn)新的業(yè)務功能即可,實現(xiàn)在不修改已有代碼的基礎上擴展系統(tǒng)的功能万栅,達到開閉原則的要求佑钾。
Sunny軟件公司開發(fā)的CRM系統(tǒng)可以顯示各種類型的圖表,如餅狀圖和柱狀圖等烦粒,為了支持多種圖表顯示方式次绘,原始設計方案如圖1所示:
在ChartDisplay類的display()方法中存在如下代碼片段:
......if (type.equals("pie"))
{PieChart chart = new PieChart();
chart.display();}
else if (type.equals("bar")) {
BarChart chart = new BarChart();chart.display();
}
......
在該代碼中,如果需要增加一個新的圖表類撒遣,如折線圖LineChart邮偎,則需要修改ChartDisplay類的display()方法的源代碼,增加新的判斷邏輯义黎,違反了開閉原則禾进。
現(xiàn)對該系統(tǒng)進行重構,使之符合開閉原則廉涕。
在本實例中泻云,由于在ChartDisplay類的display()方法中針對每一個圖表類編程,因此增加新的圖表類不得不修改源代碼狐蜕〕璐浚可以通過抽象化的方式對系統(tǒng)進行重構,使之增加新的圖表類時無須修改源代碼层释,滿足開閉原則婆瓜。具體做法如下:
(1) 增加一個抽象圖表類AbstractChart,將各種具體圖表類作為其子類贡羔;
(2) ChartDisplay類針對抽象圖表類進行編程廉白,由客戶端來決定使用哪種具體圖表。
重構后結構如圖2所示:
在圖2中乖寒,我們引入了抽象圖表類AbstractChart猴蹂,且ChartDisplay針對抽象圖表類進行編程,并通過setChart()方法由客戶端來設置實例化的具體圖表對象楣嘁,在ChartDisplay的display()方法中調(diào)用chart對象的display()方法顯示圖表磅轻。如果需要增加一種新的圖表,如折線圖LineChart逐虚,只需要將LineChart也作為AbstractChart的子類聋溜,在客戶端向ChartDisplay中注入一個LineChart對象即可,無須修改現(xiàn)有類庫的源代碼痊班。
注意:因為xml和properties等格式的配置文件是純文本文件勤婚,可以直接通過VI編輯器或記事本進行編輯摹量,且無須編譯涤伐,因此在軟件開發(fā)中馒胆,一般不把對配置文件的修改認為是對系統(tǒng)源代碼的修改。如果一個系統(tǒng)在擴展時只涉及到修改配置文件凝果,而原有的Java代碼或C#代碼沒有做任何修改祝迂,該系統(tǒng)即可認為是一個符合開閉原則的系統(tǒng)。
文章轉載自 —— 面向對象設計原則之開閉原則