設計模式的原則
近年來(lái),大家都開(kāi)始注意設計模式。那么,到底我們?yōu)槭裁匆迷O計模式呢?這么多設計模式為什么要這么設計呢?說(shuō)實(shí)話(huà),以前我還真沒(méi)搞清楚。就是看大家一口一個(gè)"Design pattern",心就有點(diǎn)發(fā)虛。于是就買(mǎi)了本"四人幫"的設計模式,結果看得似懂非懂:看得時(shí)候好像是懂了,過(guò)一會(huì )就忘了??赡苁潜救吮容^"愚鈍"吧:))最近,有了點(diǎn)感悟。"獨樂(lè )不如眾樂(lè )",與大家分享一下,還望指教!
為什么要提倡"Design Pattern"呢?根本原因是為了代碼復用,增加可維護性。那么怎么才能實(shí)現代碼復用呢?OO界有前輩的幾個(gè)原則:"開(kāi)-閉"原則(Open Closed Principal)、里氏代換原則、合成復用原則。設計模式就是實(shí)現了這些原則,從而達到了代碼復用、增加可維護性的目的。
一、"開(kāi)-閉"原則
此原則是由"Bertrand Meyer"提出的。原文是:"Software entities should be open for extension,but closed for modification"。就是說(shuō)模塊應對擴展開(kāi)放,而對修改關(guān)閉。模塊應盡量在不修改原(是"原",指原來(lái)的代碼)代碼的情況下進(jìn)行擴展。那么怎么擴展呢?我們看工廠(chǎng)模式"factory pattern":假設中關(guān)村有一個(gè)賣(mài)盜版盤(pán)和毛片的小子,我們給他設計一"光盤(pán)銷(xiāo)售管理軟件"。我們應該先設計一"光盤(pán)"接口。如圖:
[pre]______________
|<<interface>>|
| 光盤(pán) |
|_____________|
|+賣(mài)() |
| |
|_____________|[/pre]
而盜版盤(pán)和毛片是其子類(lèi)。小子通過(guò)"DiscFactory"來(lái)管理這些光盤(pán)。代碼為:
- public class DiscFactory{
- public static 光盤(pán) getDisc( String name){
- return (光盤(pán)) Class .forName(name).getInstance();
- }
- }
有人要買(mǎi)盜版盤(pán),怎么實(shí)現呢?
- public class 小子{
- public static void main( String [] args){
- 光盤(pán) d=DiscFactory.getDisc( "盜版盤(pán)" );
- 光盤(pán).賣(mài)();
- }
- }
如果有一天,這小子良心發(fā)現了,開(kāi)始賣(mài)正版軟件。沒(méi)關(guān)系,我們只要再創(chuàng )建一個(gè)"光盤(pán)"的子類(lèi)"正版軟件"就可以了。不需要修改原結構和代碼。怎么樣?對擴展開(kāi)發(fā),對修改關(guān)閉。"開(kāi)-閉原則"
工廠(chǎng)模式是對具體產(chǎn)品進(jìn)行擴展,有的項目可能需要更多的擴展性,要對這個(gè)"工廠(chǎng)"也進(jìn)行擴展,那就成了"抽象工廠(chǎng)模式"。
二、里氏代換原則
里氏代換原則是由"Barbara Liskov"提出的。如果調用的是父類(lèi)的話(huà),那么換成子類(lèi)也完全可以運行。比如:
光盤(pán) d=new 盜版盤(pán)();
d.賣(mài)();
現在要將"盜版盤(pán)"類(lèi)改為"毛片"類(lèi),沒(méi)問(wèn)題,完全可以運行。Java編譯程序會(huì )檢查程序是否符合里氏代換原則。還記得java繼承的一個(gè)原則嗎?子類(lèi)overload方法的訪(fǎng)問(wèn)權限不能小于父類(lèi)對應方法的訪(fǎng)問(wèn)權限。比如"光盤(pán)"中的方法"賣(mài)"訪(fǎng)問(wèn)權限是"public",那么"盜版盤(pán)"和"毛片"中的"賣(mài)"方法就不能是package或private,編譯不能通過(guò)。為什么要這樣呢?你想?。喝绻?盜版盤(pán)"的"賣(mài)"方法是private。那么下面這段代碼就不能執行了:
光盤(pán) d=new 盜版盤(pán)();
d.賣(mài)();
可以說(shuō):里氏代換原則是繼承復用的一個(gè)基礎。
三、合成復用原則
就是說(shuō)要少用繼承,多用合成關(guān)系來(lái)實(shí)現。我曾經(jīng)這樣寫(xiě)過(guò)程序:有幾個(gè)類(lèi)要與數據庫打交道,就寫(xiě)了一個(gè)數據庫操作的類(lèi),然后別的跟數據庫打交道的類(lèi)都繼承這個(gè)。結果后來(lái),我修改了數據庫操作類(lèi)的一個(gè)方法,各個(gè)類(lèi)都需要改動(dòng)。"牽一發(fā)而動(dòng)全身"!面向對象是要把波動(dòng)限制在盡量小的范圍。
在Java中,應盡量針對Interface編程,而非實(shí)現類(lèi)。這樣,更換子類(lèi)不會(huì )影響調用它方法的代碼。要讓各個(gè)類(lèi)盡可能少的跟別人聯(lián)系,"不要與陌生人說(shuō)話(huà)"。這樣,城門(mén)失火,才不至于殃及池魚(yú)。擴展性和維護性才能提高
理解了這些原則,再看設計模式,只是在具體問(wèn)題上怎么實(shí)現這些原則而已。