程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 面向對象程序設計的基本原則

面向對象程序設計的基本原則

編輯:關於JAVA

所有的設計模式都是對不同的可變性的封裝,從而使系統在不同角度達到“開閉原則”的要求。

  

  在軟件軟件系統中,一個模塊設計得好不好的最主要、最重要的標志,就是該模塊在多大程度上將自己的內部數據和其他與實現有關的細節隱藏起來。一個設計得好的模塊可以將它所有的實現細節隱藏起來,徹底地將提供給外界的API和自己的實現分隔開來。這樣一來,模塊與模塊之間就可以僅僅通過彼此的API相互通信,而不理會模塊內部的工作細節。

  

  

  OO設計根本的指導原則是提高可維護性和可復用性。這些原則主要有:

  1. 開閉原則

  一個軟件實體應該對擴展開放,對修改關閉。

  在設計一個模塊的時候,就當使這個模塊可以在不被修改的前提下被擴展。換言之,就當可以在不必修改源代碼的情況下改變這個模塊的行為。

  

  如何做到既不修改,又可以擴展?

  解決問題的關鍵在於抽象化:在Java語言裡,可以給出一個或多個抽象Java類或Java接口,規定出所有的具體類必須提供的方法特征作為系統設計的抽象層。這個抽象層預見了所有的可能擴展,因此,在任何擴展情況下都不會改變。這就使得系統的抽象層不需要修改,從而滿足了—對修改關閉。

  同時,由於從抽象層導出一個或多個新的具體類可以改變系統的行為,因此系統的設計對擴展是開放的。

  

  開閉原則實際上是對“對可變性的封閉原則“:找到一個系統的可變因素,將之封裝起來。這個原則意昧著兩點:

  1) 一個可變性不應當散落在代碼的很多角落裡,而應當被封裝到一個對象裡面。同一種可變性的不同表象意昧著同一個繼承等級結構中的具體子類。

  繼承就當被看作是封裝變化的方法,而不應當被認為是從一般的對象生成特殊對象的方法。

  2) 一種可變性不應當與另一種可變性混合在一起。(所有類圖的繼承結構一般不會超過兩層,不然就意昧著將兩種不同的可變性混合在了一起。)

  

  開閉原則是總的原則,其它幾條是開閉原則的手段和工具。

  

  2. 依賴倒轉原則

  依賴倒轉原則講的是:要依賴於抽象,不要信賴於實現。

  開閉原則是目標,而達到這一目標的手段是依賴倒轉原則。

  抽象層次包含的是應用系統的商務邏輯和宏觀的、對整個系統來說重要的戰略性決定,是必然性的體現;而具體層次則含有一些次要的與實現有關的算法和邏輯,以及戰術性的決定,帶有相當大的偶然性選擇。具體層次的代碼是會經常有變動的,不能避免出現錯誤。

  抽象層次含有一個應用系統最重要的宏觀商務邏輯,是做戰略判斷和決定的地方,那麼抽象層次就應當是較為穩定的,應當是復用的重點;也應當是維護的重點。

  在很多情況下,一個Java程序需要引用一個對象。這個時候,如果這個對象有一個抽象類型的話,應當使用這個抽象類型作為變量的靜態類型。這就是針對接口編程的含義。

  一般而言,在創建一個對象時,Java語言要求使用new關鍵詞以及這個類本身。而一旦這個對象已經被創建出來,那麼就可以靈活地使用這個對象的抽象類型來引用它。比如:List employees = new Vector();因此,Java語言中創建一個對象的過程是違背“開閉原則”以及依賴倒轉原則的(因為先生成了具體的類型,再使用抽象的引用),雖然在這個類被創建出來以後,可以通過多態性使得客戶端依賴於其抽象類型。正是由於這個問題,設計模式給出了多個創建模式,特別是幾個工廠模式,用於解決對象創建過程中的依賴倒轉問題。

  工廠模式將創建一個類的實例的過程封裝起來,消費這個實例的客戶端僅僅取得實例化的結果,以及這個實例的抽象類型。當然,任何方法都無法回避Java語言所要求的new關鍵字和直接調用具體類的構造子的做法(這違背了裡氏代換原則)。簡單工廠模式將這個違反“開閉原則”和依賴倒轉原則的做法封裝到了一個類裡面,而工廠方法模式將這個違反原則的做法推遲到了具體工廠角色中。通過適當的封裝,工廠模式可以淨化大部分的結構,而將違反原則的做法孤立到易於控制的地方。

  

  聯合使用Java接口和Java抽象類:聲明類型的工作由Java接口承擔,但是同時給出的還有一個Java抽象類,為這個接口給出一個缺省實現。如果一個具體類直接實現這個Java接口的話,它就必須自行實現所有的接口;相反,如果它繼承自抽象類的話,它就可以省去一些不必要的方法,因為它可以從抽象類中自動得到這些方法的缺省實現。這其實就是缺省適配模式。

  

  依賴倒轉的缺點:

  1) 因為依賴倒轉的緣故,對象的創建很可能要使用對象工廠,以避免對具體類的直接引用,此原則的使用還會導致大量的類。對不熟悉面向對象技術的工程師來說,維護這樣的系統需要較好地面向對象的設計知識。

  2) 依賴倒轉原則假定所有的具體類都是會變化的,這也不總是正確的。有一些具體類可能相當穩定、不會發生變化,消費這個具體類實例的客戶端完全可以依賴這個具體類型,而不必為此發明一個抽象類型。

  

  3. 裡氏代換原則

  任何基類可以出現的地方,子類一定可以出現。

  開閉原則的關鍵步驟是抽象化。而基類與子類的繼承關系就是抽象化的具體體現,裡氏代換原則是對實現抽象化的具體步驟的規范。

  

  4. 合成/聚合復用原則

  要盡量使用合成/聚合,而不是繼承關系達到復用的目的。

  合成/聚合原則要求我們首先考慮合成/聚合關系,裡氏代換原則要求在使用繼承時,必須確定這個繼承關系符合一定的條件(繼承是用來封裝變化的;任何基類可以出現的地方,子類一定可以出現。)

  

  合成/聚合原則就是在一個新的對象裡面使用一些已有的對象,使之成為新對象的一部分;新的對象通過向這些對象的委派達到得復用已有功能的目的。

  

  5. 迪米特原則

  一個軟件實體應當盡可能少的其他實體發生相互作用。模塊之間的交互要少。這樣做的結果是當系統的功能需要擴展時,會相對更容易地做到對修改的關閉。

  一個對象應當對其他對象有盡可能少的了解。

  

  迪米特原則的具體操作:

  1) 優先考慮將一個類設置成不變類。不變類易於設計、實現和使用。比如Java API中的String,BigInteger等類。

  一個對象與外界的通信大體上分成兩種,一種是改變這個對象的狀態,另一種是不改變這個對象的狀態的。如果一個對象的內部狀態根本就是不可能改變的,那麼它與外界的通信當然就大大地減少。

  當涉及任何一個類的時候,都首先考慮這個類的狀態是否需要改變。即便一個類必須是可變類,在給它的屬性設置賦值方法的時候,也要保持吝啬的態度。除非真的需要,否則不要為一個屬性設置賦值方法。

  

  2) 盡量降低一個類的訪問權限。

  3) 謹慎使用Serializable,一旦將一個類設置成Serializable,就不能再在新版本中修改這個類的內部結構,包括private的方法和句段。

  4) 盡量降低成員的訪問權限。

  

  6. 接口隔離原則

  應當為客戶端提供盡可能小的單獨接口,而不要提供大的總接口。也即是使用多個專門的接口比使用單一的總接口要好。

  接口隔離原則與迪米特都是對一個軟件實體與其他的軟件實體的通信限制。迪米特原則要求盡可能地限制通信的寬度和深度,接品隔離原則要求通信的寬度盡可能地窄。這樣做的結果使一個軟件系統在功能擴展過程當中,不會將修改的壓力傳遞到其他對象。

  

  一個接口相當於劇本中的一種角色,而此角色在一個舞台上由哪一個演員來演則相當於接口的實現。因此,一個接口應當簡單地代表一個角色,而不是多個角色。如果系統涉及到多個角色的話,那麼每一個角色都應當由一個特定的接口代表。

  

  定制服務:如果客戶端僅僅需要某一些方法的話,那麼就應當向客戶端提供這些需要的方法,而不要提供不需要的方法。(向客戶端提供public接口是一種承諾,沒有必要做出不必要的承諾,過多的承諾會給系統的維護造成不必要的負擔。)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved