《JAVA與模式》重讀心得和筆記 <一. 設計原則簡言>
一、開閉原則
一個軟件實體應當對擴展開放,對修改關閉。
原文:Software entities should be open for extension, but closed for modification.
引自:Bertrand Meyer[MEYER88]
這個原則說的是,在設計一個模塊的時候,應當使這個模塊可以在不被修改的前提下被擴展。
換言之,應當可以在不必修改源代碼的情況下改變這個模塊的行為。
用面向對象的語言來講,不允許修改的是系統的抽象層,而允許擴展的是系統的實現層。
二、里氏代換原則(LSP)
如果對每一個類型為 T1 的對象 o1,都有類型為 T2 的對象 o2,使得以 T1 定義的所有程序 P
在所有的對象 o1 都被代換成 o2 時,程序 P 的行為沒有變化,那么類型 T2 是類型 T1 的子類型。
換言之,一個軟件實體如果使用的是一個基類的話,那么一定適用于其子類,而且它根本不能察覺出
基類對象和子類對象的區別。
里氏代換原則是繼承復用的基石。只有當衍生類可以替換掉基類,軟件單位的功能不會收到影響時,
基類才能真正被復用,而衍生類也才能夠在基類的基礎上增加新的行為。
反過來的代換是不成立的。即如果一個軟件實體使用的是一個子類的話,那么它不一定使用于基類。
比如,Base 是 Derived 的基類。有一個方法 method1 接受子類對象為參數:
method1(Derived d)
那么一般而已不可以有 method1(b)。 注:b 為 Base 類的實例
三、依賴倒轉原則(Dependence Inversion)
依賴倒轉原則講的是:要依賴于抽象,不要依賴于具體。
傳統的過程性系統的設計辦法傾向于使高層次的模塊依賴于低層次的模塊;抽象層次依賴于具體層次。
依賴倒轉原則是要把這個錯的依賴關系倒轉過來,這就是“依賴倒轉原則”的來由。
通常,依賴(耦合)關系分為三種:
1. 零耦合(Nil Coupling)關系:兩個類之間沒有耦合關系。
2. 具體耦合(Concrete Coupling)關系:具體性耦合發生在兩個具體的(可實例化的)類直接,經由
一個類對另一個具體類的直接引用造成。
3. 抽象耦合(Abstract Coupling)關系:抽象耦合關系發生在一個具體類和一個抽象類(或者java接口)
之間,使兩個必須發生關系的類之間存有最大的靈活性。
依賴倒轉原則要求客戶端依賴于抽象耦合。他的另一種表述是:要針對接口編程、不要針對實現編程。
通常,實現依賴倒轉原則的手段是:工廠方法模式、模板方法模式、迭代子模式(這也是 Collection 類型
在可以通過 for 、while 方式遍歷的情況下,還提供 iterator 遍歷方法供調用方使用的原因)。
四、接口隔離原則(Interface Segregation)
接口隔離原則講的是:使用多個專門的接口比使用單一的總接口要好。 換言之,從一個客戶類的角度來講:
一個類對另外一個類的依賴性應當是建立在最小的接口上的。
由于每一個接口都代表一個角色,實現一個接口的對象,在他的整個生命周期中都扮演這個角色。因此將
角色劃分清楚是系統設計的一個重要工作。因此,一個符合邏輯的推斷,不應當
將幾個不同的角色都交給同一個接口,而應當交給不同的接口。
過于臃腫的接口是對接口的污染(Interface Contamination)。
五、合成/聚合復用原則(Composite/Aggregate Reuse)
合成/聚合復用原則(CARP)經常又叫合成復用原則(CRP)。合成/聚合復用就是在一個新的對象里面使用一些
已有的對象,使之成為新對象的一部分;新的對象通過向這些對象的委派達到復用已有功能的目的。這個設計
原則有另一個更簡短的表述:要盡量使用合成/聚合,盡量不要使用繼承。
Java API 中,有幾個明顯違反這一原則的例子,其中最為著名的就是 Stack 和 Properties。前者被不當地設置
為 Vector 的子類,而 Properties 被不恰當地設置成 Hashtable 的子類。
一個 Stack 不是一個 Vector(NOT IS-A),所以 Stack 不應當設置成為 Vector 的子類。同樣地,一個 Properties
也不是一個 Hashtable。 在這兩種情況下,使用聚合比使用繼承關系更合適。
由于 Properties 繼承了 Hashtable 的行為,因而當 p 是一個 Properties 類型的對象是,p.getProperties(key)
與 p.get(key) 就會給出不同的結果。前者來自于 Properties 本身,因此會利用默認值;而后者則來自于 Hashtable,
因此不會使用默認值。
更糟糕的是,由于 Properties 是 Hashtable 的子類,因此,客戶端可以通過類型的轉換,直接使用超類的行為。
比如,Properties 假定所有的鍵和值都是 String 類型的,如果不是,就會導致運行崩潰。但是,客戶端完全可以
通過 Hashtable 提供的行為加入任意類型的鍵和值,繞過 Properties 的接口,并導致 Properties 的內部矛盾和
崩潰。
這樣說來,Properties 其實僅僅是有一些 Hashtable 的屬性的,換言之,這是一個 "Has-A" 的關系,而不是一個
"Is-A" 的關系。
六、迪米特法則(LoD)
迪米特法則(Law of Demeter)又叫做最少知識原則(Least Knowledge Principle),就是說,一個對象應當對其他
對象有盡可能少的了解。
迪米特法則最初是用來作為面向對象的系統設計風格的一種法則,這條法則實際上是很多著名系統,比如火星登錄軟件
系統、木星的歐羅巴衛星軌道飛船的軟件系統的指導設計原則。
關于迪米特法則,比較有代表性的幾種描述如下:
1. 只與你直接的朋友們通信(Only talk to your immediate friends)
2. 不要跟“陌生人”說話(Don't talk to strangers)
3. 每一個軟件單位對其他的單位都只有最少的知識,而且局限于那些與本單位密切相關的軟件單位。
迪米特法則的主要用意是控制信息的過載。在將迪米特法則運用到系統設計中時,要注意下面的幾點:
1. 在類的劃分上,應當創建有弱耦合的類。類之間的耦合越弱,就越有利于復用。一個處在弱耦合中的類一旦被修改,
不會對有關系的類造成波及。
2. 在類的結構設計上,每一個類都應當盡量降低成員的訪問權限(Accessibility)。換言之,一個類包裝好各自的
private 狀態(自己的“秘密”)。 這樣一來,想要了解其中的一個類的意義時,不需要了解很多別的類的細節。一個
類不應當 public 自己的屬性,而應當提供取值和賦值方法讓外界間接訪問自己的屬性。
3. 在類的設計上,只要有可能,一個類應當設計成不變類。
4. 在對其他類的引用上,一個對象對其對象的引用應當降到最低。
posted on 2007-08-20 21:02 Samuel.Mo 閱讀(252) 評論(0) 編輯 收藏 所屬分類: Java設計模式