面向對象六大原則

2020-12-06 騰訊網

這篇文章主要講的是面向對象設計中,應該遵循的六大原則。只有掌握了這些原則,才能更好的理解設計模式。

我們接下來要介紹以下6個內容。

單一職責原則——SRP

開閉原則——OCP

裡氏替換原則——LSP

依賴倒置原則——DIP

接口隔離原則——ISP

迪米特原則——LOD

0x01: 單一職責原則

單一職責原則的定義是就一個類而言,應該僅有一個引起他變化的原因。也就是說一個類應該只負責一件事情。如果一個類負責了方法M1,方法M2兩個不同的事情,當M1方法發生變化的時候,我們需要修改這個類的M1方法,但是這個時候就有可能導致M2方法不能工作。這個不是我們期待的,但是由於這種設計卻很有可能發生。所以這個時候,我們需要把M1方法,M2方法單獨分離成兩個類。讓每個類只專心處理自己的方法。

單一職責原則的好處如下:

可以降低類的複雜度,一個類只負責一項職責,這樣邏輯也簡單很多

提高類的可讀性,和系統的維護性,因為不會有其他奇怪的方法來幹擾我們理解這個類的含義

當發生變化的時候,能將變化的影響降到最小,因為只會在這個類中做出修改。

0x02: 開閉原則

開閉原則和單一職責原則一樣,是非常基礎而且一般是常識的原則。開閉原則的定義是軟體中的對象(類,模塊,函數等)應該對於擴展是開放的,但是對於修改是關閉的。

當需求發生改變的時候,我們需要對代碼進行修改,這個時候我們應該儘量去擴展原來的代碼,而不是去修改原來的代碼,因為這樣可能會引起更多的問題。

這個準則和單一職責原則一樣,是一個大家都這樣去認為但是又沒規定具體該如何去做的一種原則。

開閉原則我們可以用一種方式來確保他,我們用抽象去構建框架,用實現擴展細節。這樣當發生修改的時候,我們就直接用抽象了派生一個具體類去實現修改。

0x03: 裡氏替換原則

裡氏替換原則是一個非常有用的一個概念。他的定義

如果對每一個類型為T1的對象o1,都有類型為T2的對象o2,使得以T1定義的所有程序P在所有對象o1都替換成o2的時候,程序P的行為都沒有發生變化,那麼類型T2是類型T1的子類型。

這樣說有點複雜,其實有一個簡單的定義

所有引用基類的地方必須能夠透明地使用其子類的對象。

裡氏替換原則通俗的去講就是:子類可以去擴展父類的功能,但是不能改變父類原有的功能。他包含以下幾層意思:

子類可以實現父類的抽象方法,但是不能覆蓋父類的非抽象方法。

子類可以增加自己獨有的方法。

當子類的方法重載父類的方法時候,方法的形參要比父類的方法的輸入參數更加寬鬆。

當子類的方法實現父類的抽象方法時,方法的返回值要比父類更嚴格。

裡氏替換原則之所以這樣要求是因為繼承有很多缺點,他雖然是復用代碼的一種方法,但同時繼承在一定程度上違反了封裝。父類的屬性和方法對子類都是透明的,子類可以隨意修改父類的成員。這也導致了,如果需求變更,子類對父類的方法進行一些複寫的時候,其他的子類無法正常工作。所以裡氏替換法則被提出來。

確保程序遵循裡氏替換原則可以要求我們的程序建立抽象,通過抽象去建立規範,然後用實現去擴展細節,這個是不是很耳熟,對,裡氏替換原則和開閉原則往往是相互依存的。

0x04: 依賴倒置原則

依賴倒置原則指的是一種特殊的解耦方式,使得高層次的模塊不應該依賴於低層次的模塊的實現細節的目的,依賴模塊被顛倒了。

這也是一個讓人難懂的定義,他可以簡單來說就是

高層模塊不應該依賴底層模塊,兩者都應該依賴其抽象

抽象不應該依賴細節

細節應該依賴抽象

在Java 中抽象指的是接口或者抽象類,兩者皆不能實例化。而細節就是實現類,也就是實現了接口或者繼承了抽象類的類。他是可以被實例化的。高層模塊指的是調用端,底層模塊是具體的實現類。在Java中,依賴倒置原則是指模塊間的依賴是通過抽象來發生的,實現類之間不發生直接的依賴關係,其依賴關係是通過接口是來實現的。這就是俗稱的面向接口編程。

下面有一個例子來講述這個問題。這個例子是工人用錘子來修理東西。代碼如下:

這個是一個很簡單的例子,但是如果我們要新增加一個功能,工人用 螺絲刀來修理東西,在這個類,我們發現是很難做的。因為我們Worker類依賴於一個具體的實現類Hammer。所以我們用到面向接口編程的思想,改成如下的代碼:

然後我們的Worker是通過這個接口來於與其他細節類進行依賴。代碼如下:

Hammer類與Screwdriver類實現這個接口

這樣,通過面向接口編程,我們的代碼就有了很高的擴展性,降低了代碼之間的耦合度,提高了系統的穩定性。

0x05: 接口隔離原則

接口隔離原則的定義是

客戶端不應該依賴他不需要的接口

換一種說法就是類間的依賴關係應該建立在最小的接口上。這樣說好像更難懂。我們通過一個例子來說明。我們知道在Java中一個具體類實現了一個接口,那必然就要實現接口中的所有方法。如果我們有一個類A和類B通過接口I來依賴,類B是對類A依賴的實現,這個接口I有5個方法。但是類A與類B只通過方法1,2,3依賴,然後類C與類D通過接口I來依賴,類D是對類C依賴的實現但是他們卻是通過方法1,4,5依賴。那麼是必在實現接口的時候,類B就要有實現他不需要的方法4和方法5 而類D就要實現他不需要的方法2,和方法3。這簡直就是一個災難的設計。

所以我們需要對接口進行拆分,就是把接口分成滿足依賴關係的最小接口,類B與類D不需要去實現與他們無關接口方法。比如在這個例子中,我們可以把接口拆成3個,第一個是僅僅由方法1的接口,第二個接口是包含2,3方法的,第三個接口是包含4,5方法的。

這樣,我們的設計就滿足了接口隔離原則。

以上這些設計思想用英文的第一個字母可以組成SOLID ,滿足這個5個原則的程序也被稱為滿足了SOLID準則。

0x06:迪米特原則

迪米特原則也被稱為最小知識原則,他的定義

一個對象應該對其他對象保持最小的了解。

因為類與類之間的關係越密切,耦合度越大,當一個類發生改變時,對另一個類的影響也越大,所以這也是我們提倡的軟體編程的總的原則:低耦合,高內聚。

迪米特法則還有一個更簡單的定義

只與直接的朋友通信。首先來解釋一下什麼是直接的朋友:每個對象都會與其他對象有耦合關係,只要兩個對象之間有耦合關係,我們就說這兩個對象之間是朋友關係。耦合的方式很多,依賴、關聯、組合、聚合等。其中,我們稱出現成員變量、方法參數、方法返回值中的類為直接的朋友,而出現在局部變量中的類則不是直接的朋友。也就是說,陌生的類最好不要作為局部變量的形式出現在類的內部。

這裡我們可以用一個現實生活中的例子來講解一下。比如我們需要一張CD,我們可能去音像店去問老闆有沒有我們需要的那張CD,老闆說現在沒有,等有的時候你們來拿就行了。在這裡我們不需要關心老闆是從哪裡,怎麼獲得的那張CD,我們只和老闆(直接朋友)溝通,至於老闆從他的朋友那裡通過何種條件得到的CD,我們不關心,我們不和老闆的朋友(陌生人)進行通信,這個就是迪米特的一個應用。說白了,就是一種中介的方式。我們通過老闆這個中介來和真正提供CD的人發生聯繫。

總結

到這裡,面向對象的六大原則,就寫完了。我們看出來,這些原則其實都是應對不斷改變的需求。每當需求變化的時候,我們利用這些原則來使我們的代碼改動量最小,而且所造成的影響也是最小的。但是我們在看這些原則的時候,我們會發現很多原則並沒有提供一種公式化的結論,而即使提供了公式化的結論的原則也只是建議去這樣做。這是因為,這些設計原則本來就是從很多實際的代碼中提取出來的,他是一個經驗化的結論。怎麼去用它,用好它,就要依靠設計者的經驗。否則一味著去使用設計原則可能會使代碼出現過度設計的情況。大多數的原則都是通過提取出抽象和接口來實現,如果發生過度的設計,就會出現很多抽象類和接口,增加了系統的複雜度。讓本來很小的項目變得很龐大,當然這也是Java的特性(任何的小項目都會做成中型的項目)。

相關焦點

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