明天就是五一了,先祝各位老友們五一快樂。
      公司終于讓我做設(shè)計了,哈哈,不過是詳細設(shè)計,還沒有到系統(tǒng)的份上。不還我還是比較滿意的,以前有辭職的想法,現(xiàn)在,怎么也要等這個項目做完之后再說了。
      這段時間一直在研究“面向?qū)ο笤O(shè)計的原則”,以下是學(xué)習(xí)的一點經(jīng)驗:
      1.類的設(shè)計原則
         在網(wǎng)上,一般認為燈的設(shè)計原則有五類,如下:
   1)SRP,單一職責(zé)原則,一個類應(yīng)該有且只有一個改變的理由。 
                  所謂單一職責(zé)原則,就是就一個類而言,應(yīng)該僅有一個引起它的變化的原因。換句話說,一個類的功能要單一,只做與它相關(guān)的事情。
  這個原則是最簡單、最容易理解,卻是最不容易做到的事情。這個原則的道理誰都理解,可是在實踐中呢?

  我們來看一個例子:

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的頁面。這個類的代碼我只截取了里面很少的一部分,絕大部分的代碼我都省略掉了。這段代碼寫到最后是越來越混亂,直到最后失敗。

  對照著這個例子,我們再來分析一下為什么要遵守單一職責(zé)愿則:

  第一、有助于我們分析和編碼的思路的清晰。當(dāng)你的代碼里有了三層或以上的if語句或for語句的嵌套的時候,你不要跟我說,你已經(jīng)把問題分析得很清楚了。多層嵌套的if或for語句只能說明你還沒有把問題分析清楚。

  第二、使我們的編碼、測試和維護變得簡單。

  第三、將一個個復(fù)雜的問題簡單化以后,易于代碼的重用。當(dāng)你的代碼的多個功能攪和在一起的時候,你是沒辦法考慮代碼的重用的,因為你的每一處代碼都有不同。

  第四、易于系統(tǒng)的擴展。 
 2)OCP,開放封閉原則,你應(yīng)該能夠不用修改原有類就能擴展一個類的行為。 
               “開一閉”原則講的是:一個軟件實體應(yīng)當(dāng)對擴展開放,對修改關(guān)閉。 這個規(guī)則說的是,在設(shè)計一個模塊的時候,應(yīng)當(dāng)使這個模塊可以在不被修改的前提下被擴展。 從另外一個角度講,就是所謂的“對可變性封裝原則”。“對可變性封裝原則”意味著兩點: 1 .一種可變性不應(yīng)當(dāng)散落在代碼的很多角落里,而應(yīng)當(dāng)被封裝到一個對象里面。同一種可變性的不同表象意味著同一個繼承等級結(jié)構(gòu)中的具體子類。 2.一種可變性不應(yīng)當(dāng)與另一種可變性混合在一起。即類圖的繼承結(jié)構(gòu)一般不應(yīng)超過兩層。 做到“開—閉”原則不是一件容易的事,但是也有很多規(guī)律可循,這些規(guī)律同樣也是設(shè)計原則,它們是實現(xiàn)開—閉原則的工具
  3)  LSP,Liskov替換原則,派生類要與其基類自相容。 
                   里氏代換原則:就是子類代替父類,程序或者代碼的行為不變。例如如果對每一個類型為T1的對象o1,都有類型為T2的對象o2,使得以T1定義的所有程序P在所有對象o1都換成o2時,程序P的行為沒有變化,那么類型T2是T1的子類型。 即如果一個軟件實體使用的是基類的話那么也一定適用于子類。但反過來的代換不成立。 如果有兩個具體類A和B之間的關(guān)系違反了里氏代換原則,可以在以下兩種重構(gòu)方案中選擇一種: 1 創(chuàng)建一個新的抽象類C,作為兩個具體類的超類,將A和B共同的行為移動到C中,從而解決A和B行為不完全一致的問題。 2 從B到A的繼承關(guān)系改寫為委派關(guān)系。 
 4) DIP,依賴倒置原則,依賴于抽象而不是實現(xiàn)。 
                  依賴倒轉(zhuǎn)原則講的是:要依賴于抽象,不要依賴于具體。即針對接口編程,不要針對實現(xiàn)編程。針對接口編程的意思是,應(yīng)當(dāng)使用接口和抽象類進行變量的類型聲明、參量的類型聲明,方法的返還類型聲明,以及數(shù)據(jù)類型的轉(zhuǎn)換等。不要針對實現(xiàn)編程的意思就是說,不應(yīng)當(dāng)使用具體類進行變量的類型聲明、參量的類型聲明,方法的返還類型聲明,以及數(shù)據(jù)類型的轉(zhuǎn)換等。 依賴倒轉(zhuǎn)原則雖然強大,但卻不易實現(xiàn),因為依賴倒轉(zhuǎn)的緣故,對象的創(chuàng)建很可能要使用對象工廠,以避免對具體類的直接引用,此原則的使用還會導(dǎo)致大量的類。維護這樣的系統(tǒng)需要較好的面向?qū)ο蟮脑O(shè)計知識。 此外,依賴倒轉(zhuǎn)原則假定所有的具體類都是變化的,這也不總是正確的。有一些具體類可能是相當(dāng)穩(wěn)定、不會發(fā)生變化的,消費這個具體類實例的客戶端完全可以依賴于這個具體類。
  5) ISP,接口隔離原則,客戶只要關(guān)注它們所需的接口。 
                  接口隔離原則講的是:使用多個專門的接口比使用單一的接口要好。從客戶的角度來說:一個類對另外一個類的依賴性應(yīng)當(dāng)是建立在最小的接口上的。如果客戶端只需要某一些方法的話,那么就應(yīng)當(dāng)向客戶端提供這些需要的方法,而不要提供不需要的方法。提供接口意味著向客戶端作出承諾,過多的承諾會給系統(tǒng)的維護造成不必要的負擔(dān)。 

         2.包原則

      REP,重用發(fā)布等價原則,重用的粒度就是發(fā)布的粒度。 
      CCP,共同封閉原則,包中的所有類對于同一類性質(zhì)的變化應(yīng)該是共同封閉的。  
      CRP,共同重用原則,一個包中的所有類應(yīng)該是共同重用的。 

      3  .包之間的耦合性原則 
       ADP,無環(huán)依賴原則,在包的依賴關(guān)系圖中不允許存在環(huán)。 
      SDP,穩(wěn)定依賴原則,朝著穩(wěn)定的方向進行依賴。 
      SAP,穩(wěn)定抽象原則,包的抽象程度應(yīng)該和其穩(wěn)定程度一致。