明天就是五一了,先祝各位老友們五一快樂。
公司終于讓我做設計了,哈哈,不過是詳細設計,還沒有到系統的份上。不還我還是比較滿意的,以前有辭職的想法,現在,怎么也要等這個項目做完之后再說了。
這段時間一直在研究“面向對象設計的原則”,以下是學習的一點經驗:
1.類的設計原則
在網上,一般認為燈的設計原則有五類,如下:
1)SRP,單一職責原則,一個類應該有且只有一個改變的理由。
所謂單一職責原則,就是就一個類而言,應該僅有一個引起它的變化的原因。換句話說,一個類的功能要單一,只做與它相關的事情。
這個原則是最簡單、最容易理解,卻是最不容易做到的事情。這個原則的道理誰都理解,可是在實踐中呢?
我們來看一個例子:
if(action.equals("load")&&tab.equals("1")){
request.setAttribute("tabId",tab);
form.set("tabId",tab);
speciManager.loadIncrement(actionForm, request, tab);
}
if(action.equals("Save")&&tab.equals("1")){
System.out.println("inter increment save action");
……
request.setAttribute("tabId",tab);
}
if(action.equals("load")&&tab.equals("2")){
request.setAttribute("tabId",tab);
form.set("tabId",tab);
speciManager.loadMeasureMent(actionForm, request, tab);
}
if(action.equals("Save")&&tab.equals("2")){
……
System.out.println("inter increment save action");
speciManager.loadIncrement(actionForm, request, tab);
form.set("tabId",tab);
request.setAttribute("tabId",tab);
}
一看就知道這個類做了太多的工作,它既要load一個tab為1的頁面和一個tab為2的頁面;又要save一個tab為1頁面和一個tab為2的頁面。這個類的代碼我只截取了里面很少的一部分,絕大部分的代碼我都省略掉了。這段代碼寫到最后是越來越混亂,直到最后失敗。
對照著這個例子,我們再來分析一下為什么要遵守單一職責愿則:
第一、有助于我們分析和編碼的思路的清晰。當你的代碼里有了三層或以上的if語句或for語句的嵌套的時候,你不要跟我說,你已經把問題分析得很清楚了。多層嵌套的if或for語句只能說明你還沒有把問題分析清楚。
第二、使我們的編碼、測試和維護變得簡單。
第三、將一個個復雜的問題簡單化以后,易于代碼的重用。當你的代碼的多個功能攪和在一起的時候,你是沒辦法考慮代碼的重用的,因為你的每一處代碼都有不同。
第四、易于系統的擴展。
2)OCP,開放封閉原則,你應該能夠不用修改原有類就能擴展一個類的行為。
“開一閉”原則講的是:一個軟件實體應當對擴展開放,對修改關閉。 這個規則說的是,在設計一個模塊的時候,應當使這個模塊可以在不被修改的前提下被擴展。 從另外一個角度講,就是所謂的“對可變性封裝原則”。“對可變性封裝原則”意味著兩點: 1 .一種可變性不應當散落在代碼的很多角落里,而應當被封裝到一個對象里面。同一種可變性的不同表象意味著同一個繼承等級結構中的具體子類。 2.一種可變性不應當與另一種可變性混合在一起。即類圖的繼承結構一般不應超過兩層。 做到“開—閉”原則不是一件容易的事,但是也有很多規律可循,這些規律同樣也是設計原則,它們是實現開—閉原則的工具
3) LSP,Liskov替換原則,派生類要與其基類自相容。
里氏代換原則:就是子類代替父類,程序或者代碼的行為不變。例如如果對每一個類型為T1的對象o1,都有類型為T2的對象o2,使得以T1定義的所有程序P在所有對象o1都換成o2時,程序P的行為沒有變化,那么類型T2是T1的子類型。 即如果一個軟件實體使用的是基類的話那么也一定適用于子類。但反過來的代換不成立。 如果有兩個具體類A和B之間的關系違反了里氏代換原則,可以在以下兩種重構方案中選擇一種: 1 創建一個新的抽象類C,作為兩個具體類的超類,將A和B共同的行為移動到C中,從而解決A和B行為不完全一致的問題。 2 從B到A的繼承關系改寫為委派關系。
4) DIP,依賴倒置原則,依賴于抽象而不是實現。
依賴倒轉原則講的是:要依賴于抽象,不要依賴于具體。即針對接口編程,不要針對實現編程。針對接口編程的意思是,應當使用接口和抽象類進行變量的類型聲明、參量的類型聲明,方法的返還類型聲明,以及數據類型的轉換等。不要針對實現編程的意思就是說,不應當使用具體類進行變量的類型聲明、參量的類型聲明,方法的返還類型聲明,以及數據類型的轉換等。 依賴倒轉原則雖然強大,但卻不易實現,因為依賴倒轉的緣故,對象的創建很可能要使用對象工廠,以避免對具體類的直接引用,此原則的使用還會導致大量的類。維護這樣的系統需要較好的面向對象的設計知識。 此外,依賴倒轉原則假定所有的具體類都是變化的,這也不總是正確的。有一些具體類可能是相當穩定、不會發生變化的,消費這個具體類實例的客戶端完全可以依賴于這個具體類。
5) ISP,接口隔離原則,客戶只要關注它們所需的接口。
接口隔離原則講的是:使用多個專門的接口比使用單一的接口要好。從客戶的角度來說:一個類對另外一個類的依賴性應當是建立在最小的接口上的。如果客戶端只需要某一些方法的話,那么就應當向客戶端提供這些需要的方法,而不要提供不需要的方法。提供接口意味著向客戶端作出承諾,過多的承諾會給系統的維護造成不必要的負擔。
2.包原則
REP,重用發布等價原則,重用的粒度就是發布的粒度。
CCP,共同封閉原則,包中的所有類對于同一類性質的變化應該是共同封閉的。
CRP,共同重用原則,一個包中的所有類應該是共同重用的。
3 .包之間的耦合性原則
ADP,無環依賴原則,在包的依賴關系圖中不允許存在環。
SDP,穩定依賴原則,朝著穩定的方向進行依賴。
SAP,穩定抽象原則,包的抽象程度應該和其穩定程度一致。