七種常見的物件導向設計原則

LXLR發表於2024-05-25
設計原則名稱 定義 使用頻率
單一職責原則 一個類只負責一個功能領域中的相應職責

四顆星

開閉原則 軟體實體應對擴充套件開發,而對修改關閉 五顆星
里氏代換原則 所有引用基類物件的地方能夠透明地使用其子類的物件 五顆星
依賴倒轉原則 抽象不應該依賴於細節,細節應該依賴於抽象 五顆星
介面隔離原則 使用多個專門的介面,而不使用單一的總介面 兩顆星
合成複用原則 儘量使用物件組合,而不是繼承來達到複用的目的 四顆星
迪米特法則 一個軟體實體應當儘可能少地與其他實體發生相互作用 三顆星

一、單一職責原則:一個類只負責一個功能領域中的相應職責

它強調一個類應該只有一個引起變化的原因。單一職責原則的使用方法:

1. 識別職責:首先,需要仔細分析類的功能,並識別出它承擔的各個職責。這些職責可以是類的功能、行為或資料操作等。

2. 分離職責:一旦識別出類的多個職責,就應該將這些職責分離到不同的類中。每個類應該只關注一個職責,並且這個職責應該被完全封裝在該類中。

3. 建立新類:對於每個分離出來的職責,可能需要建立新的類來承載它。這些新類應該具有清晰定義的介面和內部實現,以確保它們能夠獨立完成自己的職責。

4. 保持高內聚:在將職責分離到不同的類之後,要確保每個類都保持高內聚性。這意味著類內部的元素(如屬性和方法)應該緊密相關,並且共同協作以完成類的單一職責。

5. 低耦合:除了保持高內聚性外,還應該儘量減少類之間的耦合度。這可以透過使用介面、抽象類和依賴注入等技術來實現。確保類之間的依賴關係清晰且易於管理。

6. 重構現有程式碼:如果現有的程式碼違反了單一職責原則,應該考慮進行重構。透過重新組織程式碼結構、提取方法和建立新類等方式,將職責分離並封裝到合適的類中。

遵循單一職責原則的好處包括:

* 提高程式碼的可讀性和可維護性:由於每個類只關注一個職責,因此程式碼結構更加清晰,易於理解和維護。
* 降低類的複雜性:透過將職責分離到不同的類中,可以降低每個類的複雜性,使其更易於測試和除錯。
* 提高系統的可擴充套件性和靈活性:由於每個類只負責一個職責,因此可以更容易地對其進行修改和擴充套件,以適應新的需求或變化。

需要注意的是,單一職責原則並不是要求每個類都只能有一個方法或屬性,而是強調每個類應該有一個清晰定義的職責,並且這個職責應該被完全封裝在類中。在實際應用中,需要根據專案的具體情況和需求來靈活運用這一原則。

二、開閉原則:軟體實體應對擴充套件開發,而對修改關閉

這意味著軟體應該能夠在不修改其原始碼的情況下進行擴充套件。以下是開閉原則的使用方法:

1. 抽象化設計:
- 設計時,應首先識別出可能變化的點,並將這些點抽象化為介面、抽象類或基類。
- 透過定義清晰的抽象介面,我們可以確保系統的穩定性,因為具體的實現細節被隱藏在介面之後。

2. 面向介面程式設計:
- 在編寫程式碼時,應始終依賴於抽象介面,而不是具體的實現類。
- 這樣,當需要新增新功能或修改現有功能時,我們只需要建立新的實現類,而無需修改現有的程式碼。

3. 擴充套件而非修改:
- 當需要新增新功能時,應透過建立新的類來實現,而不是修改現有的類。
- 這意味著新的功能應該透過擴充套件現有系統來實現,而不是透過修改現有程式碼。

4. 使用繼承和多型:
- 繼承和多型是物件導向程式設計的重要特性,它們可以幫助我們實現開閉原則。
- 透過繼承,我們可以建立新的子類來擴充套件系統的功能。
- 透過多型(過載、重寫、介面),我們可以確保系統能夠透明地使用這些子類,而無需關心具體的實現細節。

5. 遵循單一職責原則:
- 開閉原則與單一職責原則相輔相成。確保每個類只有一個職責,這樣當需要擴充套件或修改某個功能時,我們可以更容易地定位到相關的類。

6. 使用設計模式:
- 設計模式是實現開閉原則的有力工具。例如,工廠模式、策略模式、模板方法等都可以幫助我們在不修改現有程式碼的情況下擴充套件系統的功能。

透過遵循開閉原則,我們可以構建出更加靈活、可維護和可擴充套件的軟體系統。這有助於降低系統的維護成本,提高開發效率,並使得系統能夠更好地適應未來的變化。

三、里氏代換原則:所有引用基類物件的地方能夠透明地使用其子類的物件

遵循里氏代換原則,可以確保在程式中使用基類的地方可以無縫地替換為子類,而不會導致程式行為的改變。在設計過程中,應儘量從抽象類繼承,而不是從具體類繼承,以更好地利用里氏代換原則的優勢。這有助於提高程式的可靠性、可維護性和可擴充套件性。同時,也有助於降低程式碼出錯的可能性,提高軟體的質量。

里氏代換原則的主要使用方法如下:

1. 子類擴充套件父類功能:子類可以擴充套件父類的功能,但不應改變父類原有的功能。這意味著子類在繼承父類時,除了新增新的方法實現新增功能外,應儘量避免重寫父類的方法。
2. 實現抽象方法:子類可以實現父類的抽象方法,但不應覆蓋父類的非抽象方法。這樣可以確保子類在替換父類時,不會破壞原有的程式邏輯。
3. 增加特有方法:子類中可以增加自己特有的方法,以擴充套件功能。
4. 注意方法過載與重寫:當子類的方法過載或重寫父類的方法時,需要特別注意方法的前置條件和後置條件。子類方法的前置條件(即輸入引數)應比父類方法更寬鬆,而後置條件(即方法返回的結果或產生的副作用)應與父類方法保持一致或更嚴格。

四、依賴倒轉原則:抽象不應該依賴於細節,細節應該依賴於抽象

它指導我們如何正確地消除模組間的依賴關係,實現更加靈活和可維護的程式碼結構。以下是依賴倒轉原則的使用方法:

1. 抽象化依賴:
- 依賴倒轉原則強調將模組間的依賴關係倒置為依賴抽象類或介面,而不是具體的實現類。
- 這意味著高層模組不應該依賴於低層模組的具體實現,而是應該依賴於它們的抽象。

2. 使用介面和抽象類:
- 在程式碼中,應儘量使用介面和抽象類來宣告變數型別、引數型別、方法返回型別等,而不是使用具體的類。
- 這樣做的好處是,當需要更換具體的實現時,只需要修改依賴的介面或抽象類的實現,而不需要修改所有使用到該具體類的程式碼。

3. 避免直接依賴具體類:
- 在編寫程式碼時,應儘量避免直接從具體類派生新的類,或者讓類直接依賴於具體類。
- 相反,應該透過介面或抽象類來建立依賴關係,這樣可以更加靈活地更換實現,而不需要修改大量的程式碼。

4. 依賴注入:
- 依賴注入是實現依賴倒轉原則的一種常見方式。
- 透過建構函式、方法引數或屬性等方式,將依賴的介面或抽象類的具體實現注入到需要它的類中,從而實現了對具體實現的解耦。

5. 遵循里氏替換原則:
- 里氏替換原則(Liskov Substitution Principle,LSP)是依賴倒轉原則的補充。
- 它強調子類必須能夠替換其基類,並且替換後,程式的行為不會發生變化。
- 在使用繼承時,應遵循里氏替換原則,確保子類能夠正確地替換父類,並保持程式的正確性。

透過遵循依賴倒轉原則,我們可以降低模組之間的耦合度,提高系統的可維護性和可擴充套件性。這使得程式碼更加靈活,更容易適應需求的變化和技術的演進。同時,依賴倒轉原則也是實現開閉原則的重要手段之一,有助於我們在不修改現有程式碼的情況下新增新功能或修改現有功能。

五、介面隔離原則:使用多個專門的介面,而不使用單一的總介面

它要求客戶端不應該依賴它不需要的介面,或者說一個類對另一個類的依賴性應當是最小的。這意味著我們應該儘量將介面細化,將大介面拆分成多個小介面,客戶端只需要知道它感興趣的方法即可。以下是介面隔離原則的使用方法:

1. 細化介面:
- 分析現有介面,識別出其中不同客戶端所需要的不同方法集合。
- 將介面拆分成多個更小的介面,每個介面只包含一組相關的方法,這些方法應該是高度內聚的。

2. 客戶端依賴最小化:
- 客戶端(即使用介面的類)應該只依賴它實際需要的介面,而不是一個包含眾多方法的龐大介面。
- 透過這種方式,客戶端的程式碼將更為簡潔,並且減少了不必要的依賴。

3. 避免介面汙染:
- 介面汙染是指介面中包含客戶端不需要的方法,這增加了客戶端的複雜性。
- 透過細化介面,我們可以避免介面汙染,確保每個介面都只為特定的客戶端提供所需的方法。

4. 使用委託或介面卡:
- 在某些情況下,可能無法直接拆分介面,但可以透過委託或介面卡模式來實現介面隔離。
- 委託模式允許一個物件將請求委託給另一個物件來執行,而介面卡模式可以將一個類的介面轉換為客戶端所期望的另一個介面。

5. 考慮擴充套件性:
- 在設計介面時,應考慮到未來的擴充套件性。
- 儘量避免設計過於龐大或複雜的介面,因為它們可能難以維護和擴充套件。

6. 持續重構:
- 隨著專案的進展和需求的變化,可能需要不斷地對介面進行重構,以確保它們仍然符合介面隔離原則。
- 在重構過程中,要仔細評估每個介面的使用情況,並根據需要進行拆分或合併。

透過遵循介面隔離原則,我們可以提高程式碼的可讀性、可維護性和可擴充套件性。它有助於減少類之間的耦合度,使得每個類都更加專注於自己的職責。同時,這也使得程式碼更加靈活,更容易適應未來的變化。

六:合成複用原則:儘量使用物件組合,而不是繼承來達到複用的目的

它強調透過物件組合(has-a)或物件聚合(contains-a)的方式來實現程式碼複用,而不是透過繼承關係。這種方式可以使系統更加靈活,降低類與類之間的耦合度,一個類的變化對其他類造成的影響相對較小。以下是合成複用原則的使用方法:

1. 識別可複用的物件:
- 在設計系統時,首先要識別出那些可以被複用的物件或元件。這些物件或元件通常具有穩定的介面和功能,可以在多個上下文中共享。

2. 使用組合或聚合關係:
- 在新的物件或類中,透過組合或聚合關係來使用這些可複用的物件。組合關係表示“has-a”關係,即新物件包含其他物件作為其成員;聚合關係則是一種特殊的組合關係,表示整體與部分的關係。

3. 委派呼叫已有方法:
- 新的物件或類透過委派呼叫已有物件的方法來實現複用。這意味著新物件不需要重新實現已有物件的功能,而是直接利用已有物件的方法。

4. 優先使用已存在物件:
- 在建立新物件時,應優先使用已存在的物件來達到複用的目的。這有助於減少系統的開銷,並提高資源的利用率。

5. 遵循單一職責原則:
- 合成複用原則常與單一職責原則相結合使用。確保每個物件或類都只有一個職責,這樣它們更容易被複用和組合。

6. 避免過度使用繼承:
- 繼承雖然是一種實現程式碼複用的方式,但過度使用繼承可能導致系統變得僵硬和難以維護。因此,在可能的情況下,應優先考慮使用合成複用原則來替代繼承。

透過遵循合成複用原則,我們可以構建出更加靈活、可維護和可擴充套件的軟體系統。這有助於降低系統的維護成本,提高開發效率,並使得系統能夠更好地適應未來的變化。

七:迪米特原則:一個軟體實體應當儘可能少地與其他實體發生相互作用

迪米特原則,也被稱為最少知識原則(LKP),主張一個類應該對其他類有儘可能少的瞭解。為了遵循這一原則,需要確保一個物件只與它直接相關的其他物件通訊。下面是遵循迪米特原則的一些方法:

1. 限制方法可見性:只公開必須的方法,將其他方法設定為私有,這樣就能限制其他類對該類的訪問。
2. 避免使用全域性變數:全域性變數會使得類之間的耦合度增加,因此應儘量避免使用。
3. 謹慎使用繼承:繼承會使得子類依賴於父類,因此應謹慎使用,避免不必要的依賴。
4. 使用合成複用原則:透過組合而非繼承來複用程式碼,這樣能夠降低類之間的耦合度。
5. 引入中間層:在類之間引入中間層,這樣可以降低類之間的耦合度,使得系統更易於維護。

遵循迪米特原則能夠降低類之間的耦合度,使得系統更易於維護和擴充套件。

相關文章