設計模式-六大設計原則
原創播客,如需轉載請註明出處。原文地址:https://www.cnblogs.com/ThreeDonkey/p/10231092.html
----------------------------------------------------------------------------------------------------------------------------------------------------------
筆記中提供了必要的程式碼示例,需要說明的是,大部分程式碼示例都是本人所敲程式碼並進行測試,不足之處,請大家指正~
本部落格中所有言論僅代表博主本人觀點,若有疑惑或想要與我一塊成長,敬請聯絡 [email protected]
-----------------------------------------------------------------------------------------------------------------------------------------------------------
一、序
前一陣從csdn開通了個人部落格,由於個人喜好後來搬家到部落格園。然後中間有很大一段時間沒有更新新的部落格,一是發生了許多事情沒有時間來寫部落格,二是也沒有認真深入的搞一些東西。最近又要回來了,哈哈。還是比較開心的。我當時寫部落格的初衷呢,一是為了讓所學到的東西達到一個閉環,讓所學東西有一個輸入到輸出的過程(某些東西沒法接著應用起來,通過這種輸出方式可以讓所學達到一個閉環);二是自己也是這種“開源”開放平臺的受益者,看了不知道多少前輩所寫的部落格,收益很多,然後儘量貢獻自己的一份力量,讓別人也能從自己這微薄之力中收益一下(哈哈,感覺很有成就感,不要臉.jpg);三是通過寫部落格可以與別人交流,從而發現自己的問題以及不足(前提別人看了,並且與你交流了,哈哈我相信隨著時間的推移,總會在園子裡認識很多好朋友的)以改善提高自己。
二、前言
之前粗略的瞭解過設計模式,最近又重新來了一遍。
個人觀點:設計模式真的不是生搬硬套的,前提你要有很大很大的程式碼量,然後碰到過很多的的需求,也要改過很多很多的需求,你才能真正把設計模式靈活的用起來,並感覺到設計模式的強大與魅力所在。
然後不謀而合的是最近讀了碼農翻身公眾號裡冰果老師的文章,然後我就引用下冰果老師對設計模式的觀點:
如果沒有一定的實際開發經驗與程式碼編寫量,或者為了設計模式而設計模式,那麼建議還是暫時不要管它。建議從最簡單的KISS原則開始,或者從一定的程式碼量後,追求可讀性追求更高目標,可以先做一系列重新命名提取方法等基礎重構。之後如果仍然覺得程式碼依然缺乏優雅的特性,再考慮重構到設計模式。總而言之,設計模式不應該生搬硬套塞進程式碼裡,而是應該根據需要,從程式碼中自然生長出來。
冰果老師最後還給出了建議:
總而言之,對於缺乏實際編碼經驗,或者程式碼量寫得太少的童鞋們,建議是先不要碰設計模式了。如果為了應付面試,或者想先大致瞭解以方便吹牛,那麼就從簡單的模式開始吧,首先理解其意圖任然是最重要的事情。
本菜雞還是本著自己寫部落格的初衷,然後這次寫設計模式方面的東西呢,主要是學習設計模式的思想,嗯,就這樣,以後總再自己的程式碼裡用到的。
三、宣告
本菜雞所學設計模式的主要閱讀了兩本書,一是自己購買的秦曉波老師的《設計模式之禪》(此書是通俗易懂,案例簡介明瞭);二是學校所發的耿祥義、張躍平老師的《面向物件與設計模式》(此書不太怎麼講模式,幾乎直接每個章節配兩個該模式思想的編寫的程式碼例子)。部落格中可能會出現這兩本書的大量程式碼,原書兩位老師的原話、思想,以及個人理解融匯貫通,力求做到清晰明瞭,哈哈 廢話不多說,開始。
四、六大設計原則
(1)單一職責原則(Single Responsibility Principle,簡稱SRP)
單一職責原則的定義是:應該有且僅有一個原因引起類的變化。
一個職責一個介面,但問題是“職責”沒有一個量化的標準,一個類到底要負責那些職責?這些職責怎麼去細化?這些都要從實際專案出發去考慮。
注意:單一職責原則提出了一個編寫程式的標準,用“職責”或“變化原因”來衡量藉口或類設計的是否優良,但是“職責”和“變化原因”都是不可度量的,因專案而異,因環境而異。
優點:
- 類的複雜性降低,實現什麼職責都有清晰明確的定義;
- 可讀性提高,複雜性提高,那當然可讀性提高了;
- 可維護性提高了,可讀性提高了,那當然更容易維護了;
- 變更引起的風險降低,變更是必不可少的,如果介面的單一職責做得好,一個介面修改只對相應的實現類有影響,對其他介面無影響,這對系統的拓展、維護性都有非常大的幫助。
建議:介面一定要做到單一職責,類的設計儘量要做到只有一個原因引起變化。
---恢復內容結束---
一、序
前一陣從csdn開通了個人部落格,由於個人喜好後來搬家到部落格園。然後中間有很大一段時間沒有更新新的部落格,一是發生了許多事情沒有時間來寫部落格,二是也沒有認真深入的搞一些東西。最近又要回來了,哈哈。還是比較開心的。我當時寫部落格的初衷呢,一是為了讓所學到的東西達到一個閉環,讓所學東西有一個輸入到輸出的過程(某些東西沒法接著應用起來,通過這種輸出方式可以讓所學達到一個閉環);二是自己也是這種“開源”開放平臺的受益者,看了不知道多少前輩所寫的部落格,收益很多,然後儘量貢獻自己的一份力量,讓別人也能從自己這微薄之力中收益一下(哈哈,感覺很有成就感,不要臉.jpg);三是通過寫部落格可以與別人交流,從而發現自己的問題以及不足(前提別人看了,並且與你交流了,哈哈我相信隨著時間的推移,總會在園子裡認識很多好朋友的)以改善提高自己。
二、前言
之前粗略的瞭解過設計模式,最近又重新來了一遍。
個人觀點:設計模式真的不是生搬硬套的,前提你要有很大很大的程式碼量,然後碰到過很多的的需求,也要改過很多很多的需求,你才能真正把設計模式靈活的用起來,並感覺到設計模式的強大與魅力所在。
然後不謀而合的是最近讀了碼農翻身公眾號裡冰果老師的文章,然後我就引用下冰果老師對設計模式的觀點:
如果沒有一定的實際開發經驗與程式碼編寫量,或者為了設計模式而設計模式,那麼建議還是暫時不要管它。建議從最簡單的KISS原則開始,或者從一定的程式碼量後,追求可讀性追求更高目標,可以先做一系列重新命名提取方法等基礎重構。之後如果仍然覺得程式碼依然缺乏優雅的特性,再考慮重構到設計模式。總而言之,設計模式不應該生搬硬套塞進程式碼裡,而是應該根據需要,從程式碼中自然生長出來。
冰果老師最後還給出了建議:
總而言之,對於缺乏實際編碼經驗,或者程式碼量寫得太少的童鞋們,建議是先不要碰設計模式了。如果為了應付面試,或者想先大致瞭解以方便吹牛,那麼就從簡單的模式開始吧,首先理解其意圖任然是最重要的事情。
本菜雞還是本著自己寫部落格的初衷,然後這次寫設計模式方面的東西呢,主要是學習設計模式的思想,嗯,就這樣,以後總在自己的程式碼裡用到的。
三、宣告
本菜雞所學設計模式的主要閱讀了兩本書,一是自己購買的秦曉波老師的《設計模式之禪》(此書是通俗易懂,案例簡介明瞭);二是學校所發的耿祥義、張躍平老師的《面向物件與設計模式》(此書不太怎麼講模式,幾乎直接每個章節配兩個該模式思想的編寫的程式碼例子)。部落格中可能會出現這兩本書的大量程式碼,原書兩位老師的原話、思想,以及個人理解融匯貫通,力求做到清晰明瞭,哈哈 廢話不多說,開始。
四、六大設計原則
(1)單一職責原則(Single Responsibility Principle,簡稱SRP)
單一職責原則的定義:應該有且僅有一個原因引起類的變化。
一個職責一個介面,但問題是“職責”沒有一個量化的標準,一個類到底要負責那些職責?這些職責怎麼去細化?這些都要從實際專案出發去考慮。
注意:單一職責原則提出了一個編寫程式的標準,用“職責”或“變化原因”來衡量藉口或類設計的是否優良,但是“職責”和“變化原因”都是不可度量的,因專案而異,因環境而異。
優點:
- 類的複雜性降低,實現什麼職責都有清晰明確的定義;
- 可讀性提高,複雜性提高,那當然可讀性提高了;
- 可維護性提高了,可讀性提高了,那當然更容易維護了;
- 變更引起的風險降低,變更是必不可少的,如果介面的單一職責做得好,一個介面修改只對相應的實現類有影響,對其他介面無影響,這對系統的拓展、維護性都有非常大的幫助。
建議:介面一定要做到單一職責,類的設計儘量要做到只有一個原因引起變化。
(2)里氏替換原則(Liskov Substitution Principle,簡稱LSP)
里氏替換原則的定義是(第一種):如果對每一個型別為S的物件o1,都有型別為T的物件o2,使得以T定義的所有所有程式P在所有物件o1都替換為o2時,程式P的行為沒有變化,那麼型別S是型別T的子型別。
里氏替換原則的定義是(第二種): 所有引用基型別的地方必須能夠透明的使用其子類的物件。
也就是說,只要父類能夠出現的地方子類就能出現,而且替換為子類也不能產生任何錯誤或者異常,使用者可能根本就不需要這倒是父類還是子類( 此句為重點把握這一句即可理解歷史替換原則宗旨 )。但是反過來就不行,有子類出現的地方,父類未必就能適應。
里氏替換原則為良好的繼承定義了一個規範,一句簡單的定義包含了四層含義。
1、子類必須完全實現父類的方法。
我們在做系統設計時,經常會定義一個介面或者抽象類,然後編碼實現,呼叫類則直接傳入介面或者抽象類,其實這裡已經使用了里氏替換原則。
注意:(如果子類不能完全的實現父類的方法,或者父類的某些方法在子類中已經發生了“畸變”,則建議斷開父子繼承關係,採用依賴,聚合,組合關係來代替繼承。)
2、子類可以有自己的個性。
當子類有了自己的屬性和方法時,有子類出現的地方就不能用父類替換了。里氏替換原則可以正著用,但是不能翻過來用。在子類出現的地方,父類未必就可以勝任。
3、覆蓋或實現父類的方法時輸入引數可以被放大。
若子類繼承的父類後某個方法的傳入引數的型別覆蓋範圍寬於父類了,請注意這不是重寫的父類方法,而是在繼承了父類的方法後對該方法進行了過載。如此一來,你再用子類去替代父類出現的地方,執行的方法就是原父類的方法。
4、覆寫或實現父類的方法時輸出結果可以縮小。
當一個方法覆寫或過載父某個方法後,要求的返回值的覆蓋範圍要小於等於父類,這樣在用到引數的地方才能符合里氏替換原則。
(3)依賴倒置原則(Dependence Inversion Principle,DIP)
依賴倒置原則的定義:高層模組不應該依賴底層模組,兩者都因該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象;
依賴倒置原則再Java語言中的表現就是:
1、模組間的依賴通過抽象發生,實現類之間不發生直接的依賴關係,其依賴是通過介面或者抽象類產生的;
2、抽象類或者介面不依賴與實現類;
3、實現類依賴介面或者抽象類;
總結:精髓所在就是面向介面程式設計。
(4)介面隔離原則(Interface Segregation Principle)
介面隔離原則的定義(第一種):客戶端不應該依賴他不需要的介面。
介面隔離原則的定義(第二種):類間的依賴關係應該建立在最小的介面上。
第一種定義:“客戶端不應該他不需要的介面”,那依賴什麼,依賴他需要的介面,客戶端需要什麼介面就提供什麼介面,把不需要的介面剔除,對介面進行細化,保證介面的純潔性。;
第二種定定義:“類間的依賴關係應該建立在最小的介面上”他要求也是最小的介面,介面細化,介面純潔;
我們把兩個定義概括為一句話:建立單一介面,不要建立臃腫龐大的介面。介面儘量細化,介面中的方法儘量少。
注意:(介面隔離原則與單一職責原則的審視視角是不同的,單一職責要求的類和介面職責單一,注重的是職責,這是業務上的劃分,而介面隔離原則的要求是介面中的方法儘量少。)
介面隔離原則是對介面進行規範約束,其包含一下4層含義:
1、介面儘量小
介面儘量要小,但是不要違背單一職責原則(根據介面隔離原則拆分介面時,首先必須滿足單一職責原則)。
2、介面要高內聚
提高介面、類、模組的處理能力,減少對外的互動。
3、定製服務
一個系統或者系統內的模組之間必然會有耦合,有耦合就要有互相訪問的介面我們設計時就需要為各個訪問者(即客戶端)定製服務,什麼是定製服務?就是隻提供訪問者需要的方法。
4、介面設計是有限度的
介面設計的粒度越小,系統就越靈活,但是靈活的同時也帶來結構的複雜化,開發難度增加,所以介面的設計一定要注意適度,這個度通常要根據經驗來判斷。
(5)迪米特法則(Law of Demeter,LOD)也成為最少知識原則(Least Knowledge Principle,LKP)
一個物件應該對其他物件有最最少的瞭解。一個類應該對自己耦合的類知道的最少,你內部是如何複雜的實現與我無關,我只要知道你提供的public方法。
迪米特法則對類間的低耦合提出了明確的要求,其包含以下四層含義。
迪米特法則的核心概念就是類間解耦,弱耦合,只有弱耦合了以後,累的複用率才能提高。
(6)開閉原則(Open Closed Principle)
開閉原則定義:一個軟體實體如類、模組和函式應該對拓展開放,對修改關閉。
開閉原則已經非常明確的告訴我們:軟體實體應該對拓展開放,對修改關閉,其含義是說一個軟體實體應該通過拓展來實現變化,而不是通過修改已有的程式碼來實現變化。
開閉原則的重要性:
1.開閉原則對測試的影響:所有投產的程式碼都是有意義的,並且接受系統規範的約束,而且都是經過了“千錘百煉”的測試,保證了起正確性以及健壯性。如果我們要修改了原有程式碼,則要重新對原有測試流程再進行一遍。如果我們通過拓展,而不是修改來應對變化,只需要保證新新增的程式碼的測試正確就行。
2.開閉原則可以提高複用性:所有的邏輯都是從原子的邏輯組合而來的的,只有粒度越小,被複用的可能性就越大。
3.開閉原則可以提高可維護性:投產後的軟體,要進行拓展是比較容易的,要進行修改是複雜的。
4.面向物件開發的要求:萬物皆物件,萬物皆運動,有運動就有變化,如何能夠快速應對變化,就要能夠快速去拓展應對變化,要比修改應對變化更容易。
如何使用開閉原則:
1.抽象約束:
抽象對一組事物的通用描述,沒有具體實現,也就表示他可以有非常多的可能性,可以跟隨需求變化而變化。
(1).通過介面或者抽象類約束拓展,對拓展進行邊界限定,不允許出現在介面或者抽象類中不存在的public方法
(2).引數型別、引用物件儘量使用介面或者抽象類而不是實現類。
(3).抽象儘量保持穩定,一旦確定即不允許修改。
2.元資料(metadata)控制模組行為
儘量通過元資料來控制程式的行為。什麼是元資料?用來描述環境和資料的資料,通俗的說也就是配置引數,引數可以從檔案中獲得,也可以從資料庫中獲得。
3.制定專案章程
在團隊中建立章程,因為章程中指定了所有開發人員都必須遵守的約定,對專案來說,約定優於配置。
4.封裝變化
將相同的變化封裝到一個介面或者抽象類中,將不同的變化封裝到不同的介面或者抽象類中。
開閉原則是重中之重,是最基礎的原則,是其他五大原則的精神領袖,開閉原則只是個規則,擁抱變化,並不侷限於這六大原則,但在專案中應該儘量使用者六大原則。開閉原則只是一個終極目標,任何人都無法百分之百做到,但朝著這個方向努力,可以非常顯著地改善一個系統架構,做到“擁抱變化”。