面向對象設計(OOD):迪米特法則(LoD)

2021-01-15 酷扯兒

本文轉載自【微信公眾號:碼磚雜役,ID:whatis9527want】

迪米特法則(LoD:Law of Demeter)又叫最少知識原則(LKP:Least Knowledge Principle ),是由Ian Holland於1987年提出來的,指的是一個類/模塊對其他的類/模塊有越少的了解越好。簡言之:talk only to your immediate friends(只跟你最親密的朋友交談),不跟陌生人說話。

高內聚低耦合

軟體設計有一個meta rule:高內聚,低耦合。

內聚是從功能角度來度量模塊內的聯繫緊密度,一個好的內聚模塊應該恰好專注於完成一個事情,緊密相關的功能代碼才應該放置在一起。

耦合是軟體結構中模塊間的關聯複雜度,是依賴關係的度量,當然模塊間的依賴是無法完全避免的,孤立的模塊可能也沒什麼卵用,但軟體工程師應當樹立一個意識:即吾輩應該向簡化依賴關係的方向努力。

在軟體設計中,經常用內聚和耦合作為衡量模塊獨立性的尺度,許多OOD設計原則都是為了幫助達成這2個設計目標,鬆散、複雜的依賴關係是可信、可讀性、可維護性的大敵。

為什麼要降低耦合性?

迪米特法則的初衷就是為了降低耦合。降低模塊間的聯繫度,有利於提升模塊的獨立性,高獨立性的模塊受別的模塊改動的影響小,如果修改一個模塊,很多模塊受影響(比如引起編譯錯誤,或者需要重新構建),則是一件蛋疼的事。

模塊間的耦合強,意味著修改模塊A,所有依賴A的其他模塊,都需要配合修改和重新構建,需要協作的事情總是比可單獨完成的事情更棘手,複雜性是穩定性的大敵。相互block會導致延誤項目進展,好的設計應該追求更高的獨立性,高獨立性意味花在溝通上的成本更低,獨立性跟複雜性幾乎是互斥的,越耦合越複雜。

怎麼降低耦合性?

1. 單一職責讓代碼可讀性更強,可維護性更好,且更容易被復用,單一職責的理念貫穿於軟體設計的各個方面,不僅僅適用於類和函數的設計,也適用於模塊劃分,文件拆分。比如你應該讓一個函數專注於一件事情從而提高它的健壯性和可復用性,比如你不應該設計巨類從而避免讓你為類命名而頭疼,比如你應該讓文件保持簡潔短小,而不是隨意的把不相干的東西塞進來像垃圾一樣堆在一起。單一職責為軟體設計提高良好的指引,大多數STD C API都符合單一職責的原則,從最初的STD C API發展至今已有幾十年,但這些API無論數量還是函數原型都很少變化(只是為了安全加了一些防護,比如strncpy, strcat_s),可見,設計良好的接口才會有強盛的生命力。

2. 設計類的時候,要秉持最少知識原則,這表示應該降低成員的訪問權限,儘量減少接口暴露:考慮私有化成員變量,不需要公開的成員函數不公開。

3. 不需要被其他模塊調用的全局函數,應該添加static修飾從而將它限於模塊內,避免汙染全局空間,維護最小夠用的接口集,最小的接口集往往代表著最小的依賴。

4. 在編寫c文件的時候,要謹慎處理include,僅需include必須的頭文件,遵從頭文件包含自給自足原則(包含必要的頭文件,且只包含必須的頭文件)。包含不必要的頭文件,不僅僅意味著更長的編譯時間(源文件的預處理階段展開會得到更多內容),而且意味著該文件依賴的任何其他文件的修改都會導致它的重新構建。

5. 消息機制是模塊解耦的慣用手段,不僅限於跨進程的消息機制,也包括進程內模塊間的消息機制。模塊A與B要耦合,則可能需要相互包含頭文件,相互識別對方模塊的符號,消息機制提供了另一種思路,可以通過發送消息的方式,去驅動另一個模塊doSomething,也可以通過消息,把模塊內的信息發送給其他模塊。

6. 門面模式(Facede)和中介者模式(Mediator)都是迪米特法則的應用實例,它們都源自生活。門面模式解決的是將一對多轉變為更簡單的一對一,比如開一個公司,原先需要去各個不同的政府部門辦各種證明,改革之後,只有一個部門對外接口,這種好處是顯而易見的,它把複雜性從外部轉移到了模塊內部,政府內部封裝邏輯並暴露單一界面。中介者模式可以用房屋買賣來舉例,它避免房屋買賣雙方直接溝通,中介居中溝通協調,簡化耦合鬆散的關係。門面和中介兩種模式稍微有些不同,門面更多的是一個模塊要call或者use多個其他模塊,是單向的;而中介模式通過引入中介者這個角色,解決了相互call或者use的依賴問題。

不要盲信

迪米特法則不希望模塊或類之間建立直接的聯繫,如果需要也希望通過類似友元的方式來完成,因此它有可能造成大量中介類,這些類之所以存在完全是為了傳遞類之間的相互調用關係,這在一定程度上增加了系統的複雜度。

另外,遵循類之間的迪米特法則會是一個系統的局部設計簡化,因為每一個局部都不會和遠距離的對象有直接的關聯。但是,這也會造成系統的不同模塊之間的通信效率降低,也會使系統的不同模塊之間不容易協調。

迪米特法則是OOD的一個設計指引,如何正確、恰當的使用,取決於你的經驗和悟性,你懂我意思吧?

本文轉載自【微信公眾號:碼磚雜役,ID:whatis9527want】

相關焦點

  • Unity遊戲開發:C Sharp進階之面向對象編程
    C進階之面向對象編程深入淺出的C#進階課程在了解C#基礎語法之上,進一步學習面向對象(OOP)編程技術和.NET框架,並深入講解在實踐中總結出的OOP設計理念。學完本課程,即可設計出優質的面向對象程序,並可在Unity中用C#來開發所有腳本。
  • 面向對象的六原則一法則,而現實中只需要一個原則:老婆,我錯了
    所謂的高內聚就是一個代碼模塊只完成一項功能,在面向對象中,如果只讓一個類完成它該做的事,而不涉及與它無關的領域就是踐行了高內聚的原則,這個類就只有單一職責。我們都知道一句話叫」因為專注,所以專業」,一個對象如果承擔太多的職責,那麼註定它什麼都做不好。
  • 如何以面向對象的思想設計有限狀態機
    那要怎樣設計代碼量少,又不需要以遍歷狀態轉移表的形式從而花費大量時間的狀態機呢?這個時候就需要以面向對象的思想來設計有限狀態機。面向對象法設計狀態機面向對象基本概念以面向對象的思想實現的狀態機,大量涉及了對於函數指針的用法,必須對這個概念比較熟悉上述所提到了兩個設計方法都是基於面向過程的一種設計思想,面向過程編程(POP)是一種以過程為中心的編程思想,以正在發生的事件為主要目標,指導開發者利用算法作為基本構建塊構建複雜系統。
  • 面向對象技術在單片機系統設計中的應用
    面向對象的設計方法和技術與單片機系統設計相結合就產生了面向對象的單片機系統設計,其主要思路是把單片機系統的每個接口電路都看成了一個一個的對象。單片機系統設計的任務也就變成了各接口模塊對象的組合,這樣單片機系統開發者就可以把精力更多地用在系統設計上,特別是軟體的設計。
  • 面向對象六大原則
    這篇文章主要講的是面向對象設計中,應該遵循的六大原則。只有掌握了這些原則,才能更好的理解設計模式。 我們接下來要介紹以下6個內容。所以我們用到面向接口編程的思想,改成如下的代碼: 然後我們的Worker是通過這個接口來於與其他細節類進行依賴。代碼如下: Hammer類與Screwdriver類實現這個接口 這樣,通過面向接口編程,我們的代碼就有了很高的擴展性,降低了代碼之間的耦合度,提高了系統的穩定性。
  • 面向對象編程的災難:是時候考慮更新換代了!
    Alan Kay, 面向對象編程發明者通常,人們認為Erlang不是一種面向對象的語言。但是Erlang可能是唯一主流的面向對象語言。是的, Smalltalk當然是合適的面向對象語言——但是,並沒有得到廣泛的應用。Smalltalk和Erlang都按照面向對象編程的發明者Alan Kay最初設計的方式使用面向對象編程。
  • opencv-python獲取圖像:面向對象與面向過程
    下面是分別用面向過程與面向對象的編程方法實現讀取本地圖像和打開攝像頭兩段代碼:# -*- coding: utf-8 -*-"""面向過程的編程方法,用函數把解決問題的步驟一步一步實現。Esc 退出,窗口活動時有效breakcamera.release() #釋放攝像頭cv2.waitKey(0) #等待按下任意鍵,窗口活動時有效cv2.destroyAllWindows() #銷毀所有窗口# -*- coding: utf-8 -*-"""定義類,面向對象的編程方法
  • 六大設計原則超詳細介紹(再不理解你打我)
    若要讓IPhone滿足單一職責原則,我們就要對其進行拆分,拆分後的類圖如下:這樣設計就完美了,一個類實現了兩個接口,把兩個職責融合在一個類中。你會覺得這個Phone有兩個原因引起變化了啊,是的,但是別忘了我們是面向接口編程,我們對外公布的是接口而不是實現類。
  • 如何給女朋友解釋什麼是面向對象編程?
    女朋友拿著一本《面向對象編程》過來找我。什麼是面向對象?是要面向我寫代碼嗎?不是啦,這個面向對象的對象不是你這個對象啦。此時,我突然感受到了一股莫名的殺氣。什麼?你還有其他對象嗎?有我好看嗎?有我瘦嗎?不對。你不能有其他對象。
  • 嘿,你對象在這兒——Java 面向對象編程:類和對象
    等到我們學面向對象的時候不得不去了解一下什麼是類,什麼是對象,他倆是啥關係。關於面向對象,網上那個寫得很好的例子已經被我抄到C語言與Java的區別那篇了,感興趣的小夥伴可以點左上角的菜單去查看。那麼類和對象到底是什麼呢?類就是有某些共同特徵的實體的集合;對象就是類的實例,一個對象當然就是一個類的實例。
  • Java面向對象之接口——interface
    Java面向對象之接口——interface什麼是接口一般計算機中的接口分為接口的設計目的:從上述的顯示器例子中,不難發現,接口可以看作是設備和設備之間的通信橋梁,通過交換數據完成通信。接口表示一種規範/約束/實現者必須遵循的規範,目的就是用來約束使用者應該怎麼做。那如果沒有這些規範(接口),會出現什麼樣的問題?
  • 面向對象編程
    面向對象編程(OOP)對於初學者來說可能是一個很難理解的概念。很多書籍都是從解釋OOP開始,討論三大術語:封裝、繼承和多態性,但是解釋的效果往往讓人失望。本文希望讓程式設計師、數據科學家和python愛好者們更容易理解這個概念。我們去掉所有的行話,通過一些例子來做解說。這篇文章是關於解釋OOP的外行方式。
  • 面向對象特性之三:多態(Python進階教程)
    今天我們要講一講面向對象的第三個特性:多態;什麼叫做多態?從字面意思上理解,就是一個函數具有多種形態。本質上其實就是同一操作方法作用於不同的對象時,有著不同的解釋,執行不同的邏輯,產生不同的結果。這兩個類實例化對象後,都調用各自的「送貨」方法後,我們看到,輸出的結果是不一樣的,也就是說,它們分別執行了各自類中的方法。
  • 跟我學java編程—深入理解面向對象的繼承思想
    繼承是面向對象設計的重要思想,其核心是代碼的復用和程序功能高度的擴展性。繼承在詞典中的解釋是把前人的知識、文化、思想、財產、知識等接受過來。在面向對象中,繼承是對類而言的,新類可以繼承已有類的屬性和方法,這樣做的好處是新類可以復用原有類所有的代碼,復用的同時又可以定義新的方法和屬性來擴展原有類的功能。為了理解繼承思想,下面看一個案例。某出版機構準備要通過微信小程序實現產品在微信媒體的推廣和銷售,出版機構的產品包括圖書、音頻、視頻,圖書又分為紙書和電子書。
  • 【4】類的繼承和多態-簡易的Python面向對象教程
    前言 面向對象是所有高級語言(Python,Java,C++等)的基石,是重中之重。 這個文章系列的目的是通過簡單易懂的例子,深入淺出,讓Python學習者牢固的掌握Python面向對象的概念和方法。
  • JAVA面向對象的多態是個什麼東西?
    面向對象的三大特徵:封裝、繼承、多態。在前面已經說了過了封裝和繼承。今天就來聊聊剩下的多態。多態,從字面內容來看,就是多種形態,多種狀態。在java的面向對象中可以從以下兩個方面來講。於是我們同樣創建的動物的對象,同樣調用這個動物對象叫的方法,如果這個動物對象是貓,則會發出「喵喵」聲,而如果這個動物對象是狗,發出的聲音則成了「汪汪」。這就是不同之類之間體現出來的多態。在代碼上體現就是方法名稱,參數,返回值完全與父類相同,而不同的子類在方法體內的代碼邏輯不同。
  • 詳解Java面向對象開發方法,看清華大牛帶你深入淺出剖析
    隨著軟體開發技術的逐步發展,為了進一步提高軟體的可重用性、可擴展性和可維護性,面向對象的程式語言及面向對象設計理論應運而生,Java語言就是一種純面向對象的程式語言。一般說來,軟體開發都會經歷以下生命周期:軟體分析:分析問題領域,了解用戶的需求。
  • 光線追蹤技術的理論和實踐(面向對象)
    文本還將利用c++面向對象的方法來實現光線追蹤。原理在介紹原理之前,先考慮一個問題:我們是怎樣看到真實世界中的物體的?我們能看到物體,是因為該物體上有反射光線到達我們的眼睛。沒有任何光線傳入眼睛,我們就看不到任何東西。我們還經常看到一個物體表面能反射另一個物體。
  • 大牛級別程式設計師帶小白入門Python,花7天整理最全面向對象教程!
    Python作為人工智慧首選程式語言,也是最近大家知道比較火的程式語言,Python從設計之初就已經是一門面向對象的語言,正因為如此,在Python中創建一個類和對象是很容易的。下面有大牛級別程式設計師帶小白入門Python,花7天整理最全面向對象教程!供參考學習!
  • 圖說Java中的OOPs(面向對象編程系統)基本概念
    面向對象編程是一種編程概念,其核心思想是允許用戶創建所需要的對象,然後提供處理這些對象的方法,使用者通過操作對象而獲得運算數據。本文將以簡潔的方式對面向對象編程中的概念進行梳理。1.例如,你可以創建一個名為「Bird」的鳥類,則它可能包含烏鴉,喜鵲,麻雀,鸚鵡等對象。其屬性(數據)可以是這些鳥的顏色,體重或者身高。除此之外,你還可以為鳥類提供飛行,捕食,鳴叫等方法。2. Object(對象)你可以將對象理解為類的一個實例或者具體的一個個體。在Java中一個類可以有多個對象實例,但一個對象實例只能對應一個類。