類的基礎是抽象數據類型。抽象數據類型(ADT)是數據和對這些數據操作的集合。此“數據”爲泛指,可以是窗體,文件,鏈表,汽車,飛機,人等。
類還支持繼承和多態,因此可以認爲,抽象數據類型 + 繼承 + 多態 = 類
任何東西首先展示給人的都是外表,類需要一個良好的接口。(這裏的接口主要是指類提供的public函數的集合)
1.合理的抽象
類的接口爲隱藏具體實現而提供一種抽象,此接口應該提供一組明顯相關的操作。--情非得已別讓狗拿耗子
1.一致的抽象層
類設計時,把類看成是實現ADT的機制,每個類只實現一個ADT,若某個類實現了多個ADT,則應把這個類重新組織爲多個明確的ADT。
如某個類中一半的子程序使用一部分數據,另一半的子程序使用另一部分的數據,此時可能已經把兩個類混在一起了,可以考慮分開。
2.理解類所實現的抽象
一些類非常相似,需要仔細理解類的接口,以確定所需要的抽象是哪個。
3.相反操作
開-關;添加-刪除;激活-禁用等,設計類時,不要盲目創建相反操作,要認真考慮,是否需要。-做事情不要太順手
4.抽象性和內聚性
好的抽象通常也有很高的內聚性,如果發現某個類的內聚性很弱,不知道如何修改,可以嘗試看看這個類是否表現了一致的抽象。
2.良好的封裝
抽象是忽略實現細節來管理複雜度,而封裝是阻止看到細節。--非禮勿視
1.儘可能限制成員的可訪問性
如果暴露一個子程序不會破壞抽象的一致性,則這麼做是可行的,否則隱藏之會更好。
2.不要公開(public)數據成員
公開數據會破壞封裝性,限制對抽象的控制能力。
3.避免把私有的實現細節放入類的接口中
(可參考一中的隱藏抽象的實現細節一節的內容)把private段的內容放到類的頭文件中還是暴露了部分的實現細節,可以把類的接口和類的實現隔離開來,在類的接口文件中聲明一個指向類實現的指針。
4.避免使用友元
一般情況下友元會破壞封裝性,有些場合如設計模式中,使用友元是爲了管理複雜度。
5.讓閱讀代碼比編寫代碼更方便
這個說起來容易做起來也容易,難的是一般程序員不屑於做。-這說到心坎上了
6.留意過於緊密的耦合關係(兩個類之間關聯)
以下是一些指導建議
儘可能限制類和成員的可訪問性 避免友元類 將基類數據聲明爲private而不是protected,以降低派生類和基類的耦合 避免在類中暴露數據成員
3.類的設計和內部實現
包含(有一個的關係)纔是面向對象編程的主力技術。-聚合優先於繼承
1.萬不得已時通過private繼承來實現“有一個”的關係
某些情況下根本無法包含一個對象時,可以通過private繼承來實現。-private繼承實際是實現繼承,相當於將基類的public和protected成員以private聲明於子類
2.警惕有太多數據成員的類
研究表明,人們能記住的離散項目的個數是7±2。如果一個類有超過7個數據成員,可以考慮是否有必要分解爲更小的類。如果數據成員是整形型者字符串這類簡單數據類型,可以按7±2上限考慮,若是複雜對象,則按7±2下限考慮。-這個是否有點絕對化了,看到好多類都是超過這個數的,應該要視情況而言吧
當決定使用繼承(是一個的關係)時,考慮如下
對於每個成員函數,應該對派生類可見嗎?應該有默認的實現嗎?此默認實現可以被覆蓋(override)嗎? 對於每個數據成員,應該對派生類可見嗎?1.public繼承實現“是一個......”的關係
如果派生類不準備完全遵守基類定義的同一個接口契約,就不應該用繼承。
考慮子類是否需要進行向上類型轉換,如果不需要,那麼繼承就不是正確的實現技術。-這個很關鍵,不需要多態時應考慮聚合
2.遵循Liskov替換原則
3.派生類的成員函數不要與基類中不可覆蓋的成員函數重名
如果一個函數在基類中是私有的,派生類就不要創建一個同名的成員函數。
4.公用的接口,數據放到繼承樹中儘可能高的位置
多高算高?當把子程序移到更高層次會破壞抽象性,就該停手。
5.派生類覆蓋某個子程序,其中沒做任何操作,這種情況需要注意
6.避免讓繼承體系過深
7.儘量使用多態,避免大量的類型檢查
8.讓所有數據都是private,而非protected
當決定使用多重繼承之前,應該仔細考慮其他解決方案。
何時使用繼承,何時使用包含
-
多個類共享數據而非行爲,應該創建這些類可以包含的共用對象
-
多個類共享行爲而非數據,應該從共同的基類繼承,在基類定義共用子程序
-
多個類同時共享數據和行爲,應該從基類繼承,並在基類中定義共用的數據和行爲
-
當需要用基類控制接口時,使用繼承;當想自己控制接口時,使用包含。
-
成員函數和數據成員
- 讓類中子程序儘可能少
- 禁止隱式地產生成員函數和運算符(類似將賦值運算符聲明爲private的方式)
- 減少類所調用的不同子程序的數量(扇入扇出概念)
- 對其他類的子程序的間接調用儘可能少
儘量減小類與類之前相互合作的範圍
儘量讓下面的數字最小
- 所實例化的對象種類
- 在被實例化對象上直接調用的不同子程序數量
- 調用由其他對象返回的對象的子程序數量
4.創建類的原因
-
爲現實世界中的對象建模
-
爲抽象對象建模(經典的shape不是真實存在的)
-
降低複雜度(信息隱藏,無需考慮他們了)
-
隔離複雜度(隔離複雜算法,大型數據等)
-
隱藏實現細節
-
限制變動的影響範圍
-
隱藏全局數據
-
讓參數傳遞更順暢
-
建立中心控制點
-
代碼更易於重用
-
爲程序族做計劃
-
把相關操作包裝到一起
-
實現某種特定的重構
5.應該避免的類
- 避免創建萬能類
- 消除無關緊要的類
- 避免動詞命名的類