七種常見的面向對象設計原則
| 設計原則名稱 | 定義 | 使用頻率 |
| 單一職責原則 | 一個類只負責一個功能領域中的相應職責 |
四顆星 |
| 開閉原則 | 軟件實體應對擴展開發(fā),而對修改關閉 | 五顆星 |
| 里氏代換原則 | 所有引用基類對象的地方能夠透明地使用其子類的對象 | 五顆星 |
| 依賴倒轉原則 | 抽象不應該依賴于細節(jié),細節(jié)應該依賴于抽象 | 五顆星 |
| 接口隔離原則 | 使用多個專門的接口,而不使用單一的總接口 | 兩顆星 |
| 合成復用原則 | 盡量使用對象組合,而不是繼承來達到復用的目的 | 四顆星 |
| 迪米特法則 | 一個軟件實體應當盡可能少地與其他實體發(fā)生相互作用 | 三顆星 |
一、單一職責原則:一個類只負責一個功能領域中的相應職責
它強調一個類應該只有一個引起變化的原因。單一職責原則的使用方法:
1. 識別職責:首先,需要仔細分析類的功能,并識別出它承擔的各個職責。這些職責可以是類的功能、行為或數(shù)據(jù)操作等。
2. 分離職責:一旦識別出類的多個職責,就應該將這些職責分離到不同的類中。每個類應該只關注一個職責,并且這個職責應該被完全封裝在該類中。
3. 創(chuàng)建新類:對于每個分離出來的職責,可能需要創(chuàng)建新的類來承載它。這些新類應該具有清晰定義的接口和內部實現(xiàn),以確保它們能夠獨立完成自己的職責。
4. 保持高內聚:在將職責分離到不同的類之后,要確保每個類都保持高內聚性。這意味著類內部的元素(如屬性和方法)應該緊密相關,并且共同協(xié)作以完成類的單一職責。
5. 低耦合:除了保持高內聚性外,還應該盡量減少類之間的耦合度。這可以通過使用接口、抽象類和依賴注入等技術來實現(xiàn)。確保類之間的依賴關系清晰且易于管理。
6. 重構現(xiàn)有代碼:如果現(xiàn)有的代碼違反了單一職責原則,應該考慮進行重構。通過重新組織代碼結構、提取方法和創(chuàng)建新類等方式,將職責分離并封裝到合適的類中。
遵循單一職責原則的好處包括:
* 提高代碼的可讀性和可維護性:由于每個類只關注一個職責,因此代碼結構更加清晰,易于理解和維護。
* 降低類的復雜性:通過將職責分離到不同的類中,可以降低每個類的復雜性,使其更易于測試和調試。
* 提高系統(tǒng)的可擴展性和靈活性:由于每個類只負責一個職責,因此可以更容易地對其進行修改和擴展,以適應新的需求或變化。
需要注意的是,單一職責原則并不是要求每個類都只能有一個方法或屬性,而是強調每個類應該有一個清晰定義的職責,并且這個職責應該被完全封裝在類中。在實際應用中,需要根據(jù)項目的具體情況和需求來靈活運用這一原則。
二、開閉原則:軟件實體應對擴展開發(fā),而對修改關閉
這意味著軟件應該能夠在不修改其源代碼的情況下進行擴展。以下是開閉原則的使用方法:
1. 抽象化設計:
- 設計時,應首先識別出可能變化的點,并將這些點抽象化為接口、抽象類或基類。
- 通過定義清晰的抽象接口,我們可以確保系統(tǒng)的穩(wěn)定性,因為具體的實現(xiàn)細節(jié)被隱藏在接口之后。
2. 面向接口編程:
- 在編寫代碼時,應始終依賴于抽象接口,而不是具體的實現(xiàn)類。
- 這樣,當需要添加新功能或修改現(xiàn)有功能時,我們只需要創(chuàng)建新的實現(xiàn)類,而無需修改現(xiàn)有的代碼。
3. 擴展而非修改:
- 當需要添加新功能時,應通過創(chuàng)建新的類來實現(xiàn),而不是修改現(xiàn)有的類。
- 這意味著新的功能應該通過擴展現(xiàn)有系統(tǒng)來實現(xiàn),而不是通過修改現(xiàn)有代碼。
4. 使用繼承和多態(tài):
- 繼承和多態(tài)是面向對象編程的重要特性,它們可以幫助我們實現(xiàn)開閉原則。
- 通過繼承,我們可以創(chuàng)建新的子類來擴展系統(tǒng)的功能。
- 通過多態(tài)(重載、重寫、接口),我們可以確保系統(tǒng)能夠透明地使用這些子類,而無需關心具體的實現(xiàn)細節(jié)。
5. 遵循單一職責原則:
- 開閉原則與單一職責原則相輔相成。確保每個類只有一個職責,這樣當需要擴展或修改某個功能時,我們可以更容易地定位到相關的類。
6. 使用設計模式:
- 設計模式是實現(xiàn)開閉原則的有力工具。例如,工廠模式、策略模式、模板方法等都可以幫助我們在不修改現(xiàn)有代碼的情況下擴展系統(tǒng)的功能。
通過遵循開閉原則,我們可以構建出更加靈活、可維護和可擴展的軟件系統(tǒng)。這有助于降低系統(tǒng)的維護成本,提高開發(fā)效率,并使得系統(tǒng)能夠更好地適應未來的變化。
三、里氏代換原則:所有引用基類對象的地方能夠透明地使用其子類的對象
遵循里氏代換原則,可以確保在程序中使用基類的地方可以無縫地替換為子類,而不會導致程序行為的改變。在設計過程中,應盡量從抽象類繼承,而不是從具體類繼承,以更好地利用里氏代換原則的優(yōu)勢。這有助于提高程序的可靠性、可維護性和可擴展性。同時,也有助于降低代碼出錯的可能性,提高軟件的質量。
里氏代換原則的主要使用方法如下:
1. 子類擴展父類功能:子類可以擴展父類的功能,但不應改變父類原有的功能。這意味著子類在繼承父類時,除了添加新的方法實現(xiàn)新增功能外,應盡量避免重寫父類的方法。
2. 實現(xiàn)抽象方法:子類可以實現(xiàn)父類的抽象方法,但不應覆蓋父類的非抽象方法。這樣可以確保子類在替換父類時,不會破壞原有的程序邏輯。
3. 增加特有方法:子類中可以增加自己特有的方法,以擴展功能。
4. 注意方法重載與重寫:當子類的方法重載或重寫父類的方法時,需要特別注意方法的前置條件和后置條件。子類方法的前置條件(即輸入?yún)?shù))應比父類方法更寬松,而后置條件(即方法返回的結果或產(chǎn)生的副作用)應與父類方法保持一致或更嚴格。
四、依賴倒轉原則:抽象不應該依賴于細節(jié),細節(jié)應該依賴于抽象
它指導我們如何正確地消除模塊間的依賴關系,實現(xiàn)更加靈活和可維護的代碼結構。以下是依賴倒轉原則的使用方法:
1. 抽象化依賴:
- 依賴倒轉原則強調將模塊間的依賴關系倒置為依賴抽象類或接口,而不是具體的實現(xiàn)類。
- 這意味著高層模塊不應該依賴于低層模塊的具體實現(xiàn),而是應該依賴于它們的抽象。
2. 使用接口和抽象類:
- 在代碼中,應盡量使用接口和抽象類來聲明變量類型、參數(shù)類型、方法返回類型等,而不是使用具體的類。
- 這樣做的好處是,當需要更換具體的實現(xiàn)時,只需要修改依賴的接口或抽象類的實現(xiàn),而不需要修改所有使用到該具體類的代碼。
3. 避免直接依賴具體類:
- 在編寫代碼時,應盡量避免直接從具體類派生新的類,或者讓類直接依賴于具體類。
- 相反,應該通過接口或抽象類來建立依賴關系,這樣可以更加靈活地更換實現(xiàn),而不需要修改大量的代碼。
4. 依賴注入:
- 依賴注入是實現(xiàn)依賴倒轉原則的一種常見方式。
- 通過構造函數(shù)、方法參數(shù)或屬性等方式,將依賴的接口或抽象類的具體實現(xiàn)注入到需要它的類中,從而實現(xiàn)了對具體實現(xiàn)的解耦。
5. 遵循里氏替換原則:
- 里氏替換原則(Liskov Substitution Principle,LSP)是依賴倒轉原則的補充。
- 它強調子類必須能夠替換其基類,并且替換后,程序的行為不會發(fā)生變化。
- 在使用繼承時,應遵循里氏替換原則,確保子類能夠正確地替換父類,并保持程序的正確性。
通過遵循依賴倒轉原則,我們可以降低模塊之間的耦合度,提高系統(tǒng)的可維護性和可擴展性。這使得代碼更加靈活,更容易適應需求的變化和技術的演進。同時,依賴倒轉原則也是實現(xiàn)開閉原則的重要手段之一,有助于我們在不修改現(xiàn)有代碼的情況下添加新功能或修改現(xiàn)有功能。
五、接口隔離原則:使用多個專門的接口,而不使用單一的總接口
它要求客戶端不應該依賴它不需要的接口,或者說一個類對另一個類的依賴性應當是最小的。這意味著我們應該盡量將接口細化,將大接口拆分成多個小接口,客戶端只需要知道它感興趣的方法即可。以下是接口隔離原則的使用方法:
1. 細化接口:
- 分析現(xiàn)有接口,識別出其中不同客戶端所需要的不同方法集合。
- 將接口拆分成多個更小的接口,每個接口只包含一組相關的方法,這些方法應該是高度內聚的。
2. 客戶端依賴最小化:
- 客戶端(即使用接口的類)應該只依賴它實際需要的接口,而不是一個包含眾多方法的龐大接口。
- 通過這種方式,客戶端的代碼將更為簡潔,并且減少了不必要的依賴。
3. 避免接口污染:
- 接口污染是指接口中包含客戶端不需要的方法,這增加了客戶端的復雜性。
- 通過細化接口,我們可以避免接口污染,確保每個接口都只為特定的客戶端提供所需的方法。
4. 使用委托或適配器:
- 在某些情況下,可能無法直接拆分接口,但可以通過委托或適配器模式來實現(xiàn)接口隔離。
- 委托模式允許一個對象將請求委托給另一個對象來執(zhí)行,而適配器模式可以將一個類的接口轉換為客戶端所期望的另一個接口。
5. 考慮擴展性:
- 在設計接口時,應考慮到未來的擴展性。
- 盡量避免設計過于龐大或復雜的接口,因為它們可能難以維護和擴展。
6. 持續(xù)重構:
- 隨著項目的進展和需求的變化,可能需要不斷地對接口進行重構,以確保它們仍然符合接口隔離原則。
- 在重構過程中,要仔細評估每個接口的使用情況,并根據(jù)需要進行拆分或合并。
通過遵循接口隔離原則,我們可以提高代碼的可讀性、可維護性和可擴展性。它有助于減少類之間的耦合度,使得每個類都更加專注于自己的職責。同時,這也使得代碼更加靈活,更容易適應未來的變化。
六:合成復用原則:盡量使用對象組合,而不是繼承來達到復用的目的
它強調通過對象組合(has-a)或對象聚合(contains-a)的方式來實現(xiàn)代碼復用,而不是通過繼承關系。這種方式可以使系統(tǒng)更加靈活,降低類與類之間的耦合度,一個類的變化對其他類造成的影響相對較小。以下是合成復用原則的使用方法:
1. 識別可復用的對象:
- 在設計系統(tǒng)時,首先要識別出那些可以被復用的對象或組件。這些對象或組件通常具有穩(wěn)定的接口和功能,可以在多個上下文中共享。
2. 使用組合或聚合關系:
- 在新的對象或類中,通過組合或聚合關系來使用這些可復用的對象。組合關系表示“has-a”關系,即新對象包含其他對象作為其成員;聚合關系則是一種特殊的組合關系,表示整體與部分的關系。
3. 委派調用已有方法:
- 新的對象或類通過委派調用已有對象的方法來實現(xiàn)復用。這意味著新對象不需要重新實現(xiàn)已有對象的功能,而是直接利用已有對象的方法。
4. 優(yōu)先使用已存在對象:
- 在創(chuàng)建新對象時,應優(yōu)先使用已存在的對象來達到復用的目的。這有助于減少系統(tǒng)的開銷,并提高資源的利用率。
5. 遵循單一職責原則:
- 合成復用原則常與單一職責原則相結合使用。確保每個對象或類都只有一個職責,這樣它們更容易被復用和組合。
6. 避免過度使用繼承:
- 繼承雖然是一種實現(xiàn)代碼復用的方式,但過度使用繼承可能導致系統(tǒng)變得僵硬和難以維護。因此,在可能的情況下,應優(yōu)先考慮使用合成復用原則來替代繼承。
通過遵循合成復用原則,我們可以構建出更加靈活、可維護和可擴展的軟件系統(tǒng)。這有助于降低系統(tǒng)的維護成本,提高開發(fā)效率,并使得系統(tǒng)能夠更好地適應未來的變化。
七:迪米特原則:一個軟件實體應當盡可能少地與其他實體發(fā)生相互作用
迪米特原則,也被稱為最少知識原則(LKP),主張一個類應該對其他類有盡可能少的了解。為了遵循這一原則,需要確保一個對象只與它直接相關的其他對象通信。下面是遵循迪米特原則的一些方法:
1. 限制方法可見性:只公開必須的方法,將其他方法設置為私有,這樣就能限制其他類對該類的訪問。
2. 避免使用全局變量:全局變量會使得類之間的耦合度增加,因此應盡量避免使用。
3. 謹慎使用繼承:繼承會使得子類依賴于父類,因此應謹慎使用,避免不必要的依賴。
4. 使用合成復用原則:通過組合而非繼承來復用代碼,這樣能夠降低類之間的耦合度。
5. 引入中間層:在類之間引入中間層,這樣可以降低類之間的耦合度,使得系統(tǒng)更易于維護。
遵循迪米特原則能夠降低類之間的耦合度,使得系統(tǒng)更易于維護和擴展。
浙公網(wǎng)安備 33010602011771號