- 相關(guān)推薦
該怎么使用Java設(shè)計模式編程中的OCP開閉原則?
OCP開閉原則定義:一個軟件實體如類、模塊和函數(shù)應(yīng)該對擴展開放,對修改關(guān)閉。
問題由來:在軟件的生命周期內(nèi),因為變化、升級和維護等原因需要對軟件原有代碼進行修改時,可能會給舊代碼中引入錯誤,也可能會使我們不得不對整個功能進行重構(gòu),并且需要原有代碼經(jīng)過重新測試。
解決方案:當(dāng)軟件需要變化時,盡量通過擴展軟件實體的行為來實現(xiàn)變化,而不是通過修改已有的代碼來實現(xiàn)變化。
開閉原則是面向?qū)ο笤O(shè)計中最基礎(chǔ)的設(shè)計原則,它指導(dǎo)我們?nèi)绾谓⒎(wěn)定靈活的系統(tǒng)。開閉原則可能是設(shè)計模式六項原則中定義最模糊的一個了,它只告訴我們對擴展開放,對修改關(guān)閉,可是到底如何才能做到對擴展開放,對修改關(guān)閉,并沒有明確的告訴我們。以前,如果有人告訴我“你進行設(shè)計的時候一定要遵守開閉原則”,我會覺的他什么都沒說,但貌似又什么都說了。因為開閉原則真的太虛了。
在仔細思考以及仔細閱讀很多設(shè)計模式的文章后,終于對開閉原則有了一點認識。其實,我們遵循設(shè)計模式前面5大原則,以及使用23種設(shè)計模式的目的就是遵循開閉原則。也就是說,只要我們對前面5項原則遵守的好了,設(shè)計出的軟件自然是符合開閉原則的,這個開閉原則更像是前面五項原則遵守程度的“平均得分”,前面5項原則遵守的好,平均分自然就高,說明軟件設(shè)計開閉原則遵守的好;如果前面5項原則遵守的不好,則說明開閉原則遵守的不好。
其實筆者認為,開閉原則無非就是想表達這樣一層意思:用抽象構(gòu)建框架,用實現(xiàn)擴展細節(jié)。因為抽象靈活性好,適應(yīng)性廣,只要抽象的合理,可以基本保持軟件架構(gòu)的穩(wěn)定。而軟件中易變的細節(jié),我們用從抽象派生的實現(xiàn)類來進行擴展,當(dāng)軟件需要發(fā)生變化時,我們只需要根據(jù)需求重新派生一個實現(xiàn)類來擴展就可以了。當(dāng)然前提是我們的抽象要合理,要對需求的變更有前瞻性和預(yù)見性才行。
在開閉原則的定義中,軟件實體可以指一個軟件模塊、一個由多個類組成的局部結(jié)構(gòu)或一個獨立的類。
任何軟件都需要面臨一個很重要的問題,即它們的需求會隨時間的推移而發(fā)生變化。當(dāng)軟件系統(tǒng)需要面對新的需求時,我們應(yīng)該盡量保證系統(tǒng)的設(shè)計框架是穩(wěn)定的。如果一個軟件設(shè)計符合開閉原則,那么可以非常方便地對系統(tǒng)進行擴展,而且在擴展時無須修改現(xiàn)有代碼,使得軟件系統(tǒng)在擁有適應(yīng)性和靈活性的同時具備較好的穩(wěn)定性和延續(xù)性。隨著軟件規(guī)模越來越大,軟件壽命越來越長,軟件維護成本越來越高,設(shè)計滿足開閉原則的軟件系統(tǒng)也變得越來越重要。
為了滿足開閉原則,需要對系統(tǒng)進行抽象化設(shè)計,抽象化是開閉原則的關(guān)鍵。在Java、C#等編程語言中,可以為系統(tǒng)定義一個相對穩(wěn)定的抽象層,而將不同的實現(xiàn)行為移至具體的實現(xiàn)層中完成。在很多面向?qū)ο缶幊陶Z言中都提供了接口、抽象類等機制,可以通過它們定義系統(tǒng)的抽象層,再通過具體類來進行擴展。如果需要修改系統(tǒng)的行為,無須對抽象層進行任何改動,只需要增加新的具體類來實現(xiàn)新的業(yè)務(wù)功能即可,實現(xiàn)在不修改已有代碼的基礎(chǔ)上擴展系統(tǒng)的功能,達到開閉原則的要求。
Sunny軟件公司開發(fā)的CRM系統(tǒng)可以顯示各種類型的圖表,如餅狀圖和柱狀圖等,為了支持多種圖表顯示方式,原始設(shè)計方案如下圖所示:
在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)進行重構(gòu),使之符合開閉原則。
在本實例中,由于在ChartDisplay類的display()方法中針對每一個圖表類編程,因此增加新的圖表類不得不修改源代碼?梢酝ㄟ^抽象化的方式對系統(tǒng)進行重構(gòu),使之增加新的圖表類時無須修改源代碼,滿足開閉原則。具體做法如下:
(1) 增加一個抽象圖表類AbstractChart,將各種具體圖表類作為其子類;
(2) ChartDisplay類針對抽象圖表類進行編程,由客戶端來決定使用哪種具體圖表。
重構(gòu)后結(jié)構(gòu)如下圖所示:
在圖2中,我們引入了抽象圖表類AbstractChart,且ChartDisplay針對抽象圖表類進行編程,并通過setChart()方法由客戶端來設(shè)置實例化的具體圖表對象,在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)。
【該怎么使用Java設(shè)計模式編程中的OCP開閉原則?】相關(guān)文章:
C語言編程中使用設(shè)計模式中的原型模式的講解07-19
解析Java的設(shè)計模式編程之解釋器模式的運用05-19
Java編程中throw和throws子句的使用方法08-26
Java編程中異常處理的方法10-02
Java編程中獲取路徑的方法09-06
Java編程中this關(guān)鍵字與super關(guān)鍵字的使用方法08-23
Java線程編程中的主線程詳細介紹09-05
java教程之Java編程基礎(chǔ)09-12