7-11-23-61

一、7種設計壞味道 
1.僵化性: 很難對系統進行改動,因爲每個改動都會迫使許多對系統其他部分的其它改動。 
2.脆弱性: 對系統的改動會導致系統中和改動的地方在概念上無關的許多地方出現問題。 
3.牢固性: 很難解開系統的糾結,使之成爲一些可在其他系統中重用的組件。 
4.粘滯性: 做正確的事情比做錯誤的事情要困難。 
5.複雜性(不必要的): 設計中包含有不具任何直接好處的基礎結構。 
6.重複性(不必要的): 設計中包含有重複的結構,而該重複的結構本可以使用單一的抽象進行統一。 
7.晦澀性: 很難閱讀、理解。沒有很好地表現出意圖。 

 

二、11種原則 - Principle 
類原則 
1.單一職責原則 - Single Responsibility Principle(SRP) :就一個類而言,應該僅有一個引起它變化的原因。(職責即爲“變化的原因”。) 
2.開放-封閉原則 - Open Close Principle(OCP) :軟件實體(類、模塊、函數等)應該是可以擴展的,但是不可修改。(對於擴展是開放的,對於更改是封閉的. 關鍵是抽象.將一個功能的通用部分和實現細節部分清晰的分離開來. 開發人員應該僅僅對程序中呈現出頻繁變化的那些部分作出抽象. 拒絕不成熟的抽象和抽象本身一樣重要. ) 
3.里氏替換原則 - Liskov Substitution Principle(LSP): 子類型(subclass)必須能夠替換掉它們的基類型(superclass)。 
4.依賴倒置原則(IoCP) 或 依賴注入原則 - Dependence Inversion Principle(DIP): 抽象不應該依賴於細節。細節應該依賴於抽象。(Hollywood原則: "Don't call us, we'll call you". 程序中所有的依賴關係都應該終止於抽象類和接口。針對接口而非實現編程。 任何變量都不應該持有一個指向具體類的指針或引用。 任何類都不應該從具體類派生。任何方法都不應該覆寫他的任何基類中的已經實現了的方法。) 
5.接口隔離原則(ISP) :不應該強迫客戶依賴於它們不用的方法。 接口屬於客戶,不屬於它所在的類層次結構。 (多個面向特定用戶的接口勝於一個通用接口。) 
包內聚原則 
6.重用發佈等價原則(REP): 重用的粒度就是發佈的粒度。 
7.共同封閉原則(CCP) :包中的所有類對於同一類性質的變化應該是共同封閉的。 一個變化若對一個包產生影響, 則將對該包中的所有類產生影響, 而對於其他的包不造成任何影響。 
8.共同重用原則(CRP): 一個包中的所有類應該是共同重用的。 如果重用了包中的一個類, 那麼就要重用包中的所有類。(相互之間沒有緊密聯繫的類不應該在同一個包中。) 
包耦合原則 
9.無環依賴原則(ADP) :在包的依賴關係圖中不允許存在環。 
10.穩定依賴原則(SDP): 朝着穩定的方向進行依賴。 應該把封裝系統高層設計的軟件(比如抽象類)放進穩定的包中,不穩定的包中應該只包含那些很可能會改變的軟件(比如具體類)。 
11.穩定抽象原則(SAP) :包的抽象程度應該和其穩定程度一致。 (一個穩定的包應該也是抽象的,一個不穩定的包應該是抽象的. ) 
其它擴展原則

12.BBP(Black Box Principle)黑盒原則 :多用類的聚合,少用類的繼承。 
13.DAP(Default Abstraction Principle)缺省抽象原則: 在接口和實現接口的類之間引入一個抽象類,這個類實現了接口的大部分操作. 
14.IDP(Interface Design Principle)接口設計原則: 規劃一個接口而不是實現一個接口。 
15.DCSP(Don't Concrete Supperclass Principle):不要構造具體的超類原則 避免維護具體的超類。 
16.迪米特法則: 一個類只依賴其觸手可得的類。 

 

三、23種設計模式 - Pattern. 
創建型 
Abstract Factory(抽象工廠模式) -> (簡單工廠模式) 
Factory Method(工廠模式) 
Builder(生成器模式) 
Singleton(單件模式) -> (多例模式) 
Prototype(原型模式) 
結構型 
Adapter(適配器模式) 
Bridge(橋接模式) 
Composite(組合模式) 
Decorator(裝飾模式) 
Facade(外觀模式,門面模式) 
Flyweight(享元模式) -> (不變模式) 
Proxy(代理模式) 
行爲型 
Chain of Responsibility(職責鏈模式) 
Command(命令模式) 
Interpreter(解釋器模式) 
Iteartor(迭代器模式) 
Mediator(中介者模式) 
Memento(備忘錄模式) 
Observer(觀察者模式) 
State(狀態模式) 
Strategy(策略模式) 
TemplateMethod(模板方法模式) 
Visitor(訪問者模式) 


 

  四、61條面向對象設計的經驗

你不必嚴格遵守這些原則,違背它們也不會被處以宗教刑罰。但你應當把這些原則看成警鈴,若違背了其中的一條,那麼警鈴就會響起。Arthur J.Riel 

  (1)所有數據都應該隱藏在所在的類的內部。
  (2)類的使用者必須依賴類的共有接口,但類不能依賴它的使用者。
  (3)儘量減少類的協議中的消息。
  (4)實現所有類都理解的最基本公有接口[例如,拷貝操作(深拷貝和淺拷貝)、相等性判斷、正確輸出內容、從ASCII描述解析等等]。
  (5)不要把實現細節(例如放置共用代碼的私有函數)放到類的公有接口中。如果類的兩個方法有一段公共代碼,那麼就可以創建一個防止這些公共代碼的私有函數。
  (6)不要以用戶無法使用或不感興趣的東西擾亂類的公有接口。
  (7)類之間應該零耦合,或者只有導出耦合關係。也即,一個類要麼同另一個類毫無關係,要麼只使用另一個類的公有接口中的操作。
  (8)類應該只表示一個關鍵抽象。包中的所有類對於同一類性質的變化應該是共同封閉的。一個變化若對一個包影響,則將對包中的所有類產生影響,而對其他的包不造成任何影響 .
  (9)把相關的數據和行爲集中放置。 設計者應當留意那些通過get之類操作從別的對象中獲取數據的對象。這種類型的行爲暗示着這條經驗原則被違反了。
  (10)把不相關的信息放在另一個類中(也即:互不溝通的行爲)。朝着穩定的方向進行依賴.
  (11)確保你爲之建模的抽象概念是類,而不只是對象扮演的角色。
  (12)在水平方向上儘可能統一地分佈系統功能,也即:按照設計,頂層類應當統一地共享工作。
  (13)在你的系統中不要創建全能類/對象。對名字包含Driver、Manager、System、Susystem的類要特別多加小心。規劃一個接口而不是實現一個接口。
  (14)對公共接口中定義了大量訪問方法的類多加小心。大量訪問方法意味着相關數據和行爲沒有集中存放。
  (15)對包含太多互不溝通的行爲的類多加小心。這個問題的另一表現是在你的應用程序中的類的公有接口中創建了很多的get和set函數。
  (16)在由同用戶界面交互的面向對象模型構成的應用程序中,模型不應該依賴於界面,界面則應當依賴於模型。
  (17)儘可能地按照現實世界建模(我們常常爲了遵守系統功能分佈原則、避免全能類原則以及集中放置相關數據和行爲的原則而違背這條原則) 。
  (18)從你的設計中去除不需要的類。一般來說,我們會把這個類降級成一個屬性。
  (19)去除系統外的類。系統外的類的特點是,抽象地看它們只往系統領域發送消息但並不接受系統領域內其他類發出的消息。
  (20)不要把操作變成類。質疑任何名字是動詞或者派生自動詞的類,特別是只有一個有意義行爲的類。考慮一下那個有意義的行爲是否應當遷移到已經存在或者尚未發現的某個類中。
  (21)我們在創建應用程序的分析模型時常常引入代理類。在設計階段,我們常會發現很多代理沒有用的,應當去除。
  (22)儘量減少類的協作者的數量。一個類用到的其他類的數目應當儘量少。
  (23)儘量減少類和協作者之間傳遞的消息的數量。
  (24)儘量減少類和協作者之間的協作量,也即:減少類和協作者之間傳遞的不同消息的數量。
  (25)儘量減少類的扇出,也即:減少類定義的消息數和發送的消息數的乘積。
  (26)如果類包含另一個類的對象,那麼包含類應當給被包含的對象發送消息。也即:包含關係總是意味着使用關係。
  (27)類中定義的大多數方法都應當在大多數時間裏使用大多數數據成員。
  (28)類包含的對象數目不應當超過開發者短期記憶的容量。這個數目常常是6。 當類包含多於6個數據成員時,可以把邏輯相關的數據成員劃分爲一組,然後用一個新的包含類去包含這一組成員。
  (29)讓系統功能在窄而深的繼承體系中垂直分佈。
  (30)在實現語義約束時,最好根據類定義來實現。這常常會導致類氾濫成災,在這種情況下,約束應當在類的行爲中實現,通常是在構造函數中實現,但不是必須如此。
  (31)在類的構造函數中實現語義約束時,把約束測試放在構造函數領域所允許的儘量深的包含層次中。
  (32)約束所依賴的語義信息如果經常改變,那麼最好放在一個集中式的第3方對象中。
  (33)約束所依賴的語義信息如果很少改變,那麼最好分佈在約束所涉及的各個類中。
  (34)類必須知道它包含什麼,但是不能知道誰包含它。
  (35)共享字面範圍(也就是被同一個類所包含)的對象相互之間不應當有使用關係。
  (36)繼承只應被用來爲特化層次結構建模。
  (37)派生類必須知道基類,基類不應該知道關於它們的派生類的任何信息。
  (38)基類中的所有數據都應當是私有的,不要使用保護數據。類的設計者永遠都不應該把類的使用者不需要的東西放在公有接口中。
  (39)在理論上,繼承層次體系應當深一點,越深越好。
  (40)在實踐中,繼承層次體系的深度不應當超出一個普通人的短期記憶能力。一個廣爲接受的深度值是6。
  (41)所有的抽象類都應當是基類。
  (42)所有的基類都應當是抽象類。
  (43)把數據、行爲和/或接口的共性儘可能地放到繼承層次體系的高端。
  (44)如果兩個或更多個類共享公共數據(但沒有公共行爲),那麼應當把公共數據放在一個類中,每個共享這個數據的類都包含這個類。
  (45)如果兩個或更多個類有共同的數據和行爲(就是方法),那麼這些類的每一個都應當從一個表示了這些數據和方法的公共基類繼承。
  (46)如果兩個或更多個類共享公共接口(指的是消息,而不是方法),那麼只有他們需要被多態地使用時,他們才應當從一個公共基類繼承。
  (47)對對象類型的顯示的分情況分析一般是錯誤的。在大多數這樣的情況下,設計者應當使用多態。
  (48)對屬性值的顯示的分情況分析常常是錯誤的。類應當解耦合成一個繼承層次結構,每個屬性值都被變換成一個派生類。
  (49)不要通過繼承關係來爲類的動態語義建模。試圖用靜態語義關係來爲動態語義建模會導致在運行時切換類型。
  (50)不要把類的對象變成派生類。對任何只有一個實例的派生類都要多加小心。
  (51)如果你覺得需要在運行時刻創建新的類,那麼退後一步以認清你要創建的是對象。現在,把這些對象概括成一個類。
  (52)在派生類中用空方法(也就是什麼也不做的方法)來覆寫基類中的方法應當是非法的。
  (53)不要把可選包含同對繼承的需要相混淆。把可選包含建模成繼承會帶來氾濫成災的類。
  (54)在創建繼承層次時,試着創建可複用的框架,而不是可複用的組件。p112
  (55)如果你在設計中使用了多重繼承,先假設你犯了錯誤。如果沒犯錯誤,你需要設法證明。
  (56)只要在面向對象設計中用到了繼承,問自己兩個問題:(1)派生類是否是它繼承的那個東西的一個特殊類型?(2)基類是不是派生類的一部分?
  (57)如果你在一個面向對象設計中發現了多重繼承關係,確保沒有哪個基類實際上是另一個基類的派生類。
  (58)在面向對象設計中如果你需要在包含關係和關聯關係間作出選擇,請選擇包含關係。
  (59)不要把全局數據或全局函數用於類的對象的薄記工作。應當使用類變量或類方法。
  (60)面向對象設計者不應當讓物理設計準則來破壞他們的邏輯設計。但是,在對邏輯設計作出決策的過程中我們經常用到物理設計準則。
  (61)不要繞開公共接口去修改對象的狀態。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章