天天看點

代碼整潔之道-第6章-對象和資料結構-讀書筆記

第 6 章 對象和資料結構

  将變量設定為私有(private)有一個理由:我們不想其他人依賴這些變量。

6.1 資料抽象

  隐藏實作并非隻是在變量之間放上一個函數層那麼簡單。隐藏實作關乎抽象!類并不簡單地用取值器和指派器将其變量推向外間,而是暴露抽象接口,以便使用者無需了解資料的實作就能操作資料本體。

  我們不願暴露資料細節,更願意以抽象形态表述資料,這并不隻是用接口和 / 或指派器、取值器就萬事大吉。要以最好的方式呈現某個對象包含的資料,需要做嚴肅的思考。傻樂着亂加取值器和指派器,是最壞的選擇。

6.2 資料、對象的反對稱性

  對象把資料隐藏于抽象之後,曝露操作資料的函數。資料結構曝露其資料,沒有提供有意義的函數。他們是對立的。這種差異貌似微小,但卻有深遠的含義。

  過程式代碼(使用資料結構的代碼)便于在不改動既有資料結構的前提下添加新函數。面向對象代碼便于在不改動既有函數的前提下添加新類。反過來講也說得通:過程式代碼難以添加新資料結構,因為必須修改所有函數。面向對象代碼難以添加新函數,因為必須修改所有類。是以,對于面向對象較難的事,對于過程式代碼卻較容易,反之亦然。

  在任何一個複雜系統中,都會有需要添加新資料類型而不是新函數的時候。這時,對象和面向對象就比較合适。另一方面,也會有想要添加新函數而不是資料類型的時候。在這種情況下,過程式代碼和資料結構更合适。

6.3 得墨忒耳律

  著名的得墨忒耳律(The Law of Demeter)認為,子產品不應了解它所操作對象的内部情形。對象隐藏資料,曝露操作。這意味着對象不應通過存取器曝露其内部結構,因為這樣更像是曝露而非隐藏其内部結構。

  更準确地說,得墨忒耳律認為,類 C 的方法 f 隻應該調用以下對象的方法:

  • C
  • 由 f 建立的對象;
  • 作為參數傳遞給 f 的對象;
  • 由 C 的實體變量持有的對象。

  方法不應調用由任何函數傳回的對象的方法。

6.3.1 火車失事

  對象才涉及得墨忒耳律,資料結構沒有任何行為,則自然會曝露其内部結構,得墨忒耳律也就不适用了。

6.3.2 混雜

  一半是對象,一半是資料結構這種混合結構擁有執行操作的函數,也有公共變量或公共通路器及改值器。無論出于怎樣的初衷,公共通路器及改值器都把私有變量公開化,誘導外部函數以過程式程式使用資料結構的方式使用這些變量。

  此類混雜增加了新函數的難度,也增加了添加新資料結構的難度,兩面不讨好。應避免創造這種結構。它們的出現,展現了一種亂七八糟的設計,其作者不确定—或者更糟糕,完全無視—它們是否需要函數或類型的保護。

6.3.3 隐藏結構

  分析擷取對象的内部結構的目的,用方法來代替擷取,防止目前函數因浏覽它不該知道的對象而違反德墨忒爾律。

6.4 資料傳送對象

  最為精煉的資料結構,是一個隻有公共變量、沒有函數的類。這種資料結構有時被稱為資料傳送對象,或 DTO(Data Transfer Objects)。 DTO 是非常有用的結構,尤其是在與資料庫通信、或解析套接字傳遞的消息之類場景中。

Active Record

  Active Record 是一種特殊的 DTO 形式。它們是擁有公共(或可豆式通路的)變量的資料結構,但通常也會擁有類似 save 和 find 這樣的可浏覽方法。 Active Record 一般是對資料庫表或其他資料源的直接翻譯。

  經常發現開發者往這類資料結構中塞進業務規則方法,把這類資料結構當成對象來用。這是不智的行為,因為它導緻了資料結構和對象的混雜體。

  當然,解決方案就是把 Active Record 當做資料結構,并建立包含業務規則、隐藏内部資料(可能就是 Active Record 的實體)的獨立對象。

6.5 小結

  對象曝露行為,隐藏資料。便于添加新對象類型而不誤修改既有行為,同時也難以在既有對象中添加新行為。資料結構曝露資料,沒有明顯的行為。便于向既有資料結構添加新行為,同時也難以向既有函數添加新資料結構。

6.6 文獻