設計原則名稱 定義 使用頻率 單一職責原則 一個類只負責一個功能領域中的相應職責 四顆星 開閉原則 軟體實體應對擴展開發,而對修改關閉 五顆星 里氏代換原則 所有引用基類對象的地方能夠透明地使用其子類的對象 五顆星 依賴倒轉原則 抽象不應該依賴於細節,細節應該依賴於抽象 五顆星 介面隔離原則 使用多 ...
設計原則名稱 | 定義 | 使用頻率 |
單一職責原則 | 一個類只負責一個功能領域中的相應職責 |
四顆星 |
開閉原則 | 軟體實體應對擴展開發,而對修改關閉 | 五顆星 |
里氏代換原則 | 所有引用基類對象的地方能夠透明地使用其子類的對象 | 五顆星 |
依賴倒轉原則 | 抽象不應該依賴於細節,細節應該依賴於抽象 | 五顆星 |
介面隔離原則 | 使用多個專門的介面,而不使用單一的總介面 | 兩顆星 |
合成復用原則 | 儘量使用對象組合,而不是繼承來達到復用的目的 | 四顆星 |
迪米特法則 | 一個軟體實體應當儘可能少地與其他實體發生相互作用 | 三顆星 |
一、單一職責原則:一個類只負責一個功能領域中的相應職責
它強調一個類應該只有一個引起變化的原因。單一職責原則的使用方法:
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. 引入中間層:在類之間引入中間層,這樣可以降低類之間的耦合度,使得系統更易於維護。
遵循迪米特原則能夠降低類之間的耦合度,使得系統更易於維護和擴展。