iOS-設(shè)計模式之原則講解

目錄
  • 單一職責原則
  • 開閉原則
  • 里氏替換原則
  • 接口隔離原則
  • 依賴倒置原則
  • 迪米特法則
  • 組合/聚合復用原則(合成復用原則)

先來一張設(shè)計模型圖

設(shè)計模式.png

摘自百度百科的介紹

設(shè)計模式(Design pattern)代表了最佳的實踐耐床,通常被有經(jīng)驗的面向?qū)ο蟮能浖_發(fā)人員所采用。設(shè)計模式是軟件開發(fā)人員在軟件開發(fā)過程中面臨的一般問題的解決方案。這些解決方案是眾多軟件開發(fā)人員經(jīng)過相當長的一段時間的試驗和錯誤總結(jié)出來的菠红。

設(shè)計模式是一套被反復使用的、多數(shù)人知曉的、經(jīng)過分類編目的刷后、代碼設(shè)計經(jīng)驗的總結(jié)的畴。使用設(shè)計模式是為了重用代碼、讓代碼更容易被他人理解尝胆、保證代碼可靠性丧裁。 毫無疑問,設(shè)計模式于己于他人于系統(tǒng)都是多贏的班巩,設(shè)計模式使代碼編制真正工程化渣慕,設(shè)計模式是軟件工程的基石,如同大廈的一塊塊磚石一樣抱慌。項目中合理地運用設(shè)計模式可以完美地解決很多問題逊桦,每種模式在現(xiàn)實中都有相應的原理來與之對應,每種模式都描述了一個在我們周圍不斷重復發(fā)生的問題抑进,以及該問題的核心解決方案强经,這也是設(shè)計模式能被廣泛應用的原因。

下面從7種設(shè)計原則寺渗,23種設(shè)計模式匿情,來講解設(shè)計模式

一 設(shè)計原則
簡寫 全稱 中文名
S Single Responsibility Principle 單一職責原則
O Open Close Principle 開閉原則
L Liskov Substitution Principle 里氏替換原則
I Interface Segregation Principle 接口隔離原則
D Dependence Inversion Principle 依賴倒置原則
L Law Of Demeter 迪米特法則
C Composite/Aggregate Reuse Principle CARP 組合/聚合復用原則

前面五種被稱為面向?qū)ο笤O(shè)計中常用的SOLID原則。

1.1 單一職責原則

原文鏈接 - 面向?qū)ο笤O(shè)計原則之單一職責原則

單一職責原則是最簡單的面向?qū)ο笤O(shè)計原則信殊,它用于控制類的粒度大小炬称。定義如下

單一職責原則(Single Responsibility Principle, SRP):一個類只負責一個功能領(lǐng)域中的相應職責,或者可以定義為:就一個類而言涡拘,應該只有一個引起它變化的原因玲躯。

單一職責原則告訴我們:一個類不能太“累”!在軟件系統(tǒng)中鳄乏,一個類(大到模塊跷车,小到方法)承擔的職責越多,它被復用的可能性就越小橱野,而且一個類承擔的職責過多朽缴,就相當于將這些職責耦合在一起,當其中一個職責變化時水援,可能會影響其他職責的運作密强,因此要將這些職責進行分離,將不同的職責封裝在不同的類中蜗元,即將不同的變化原因封裝在不同的類中誓斥,如果多個職責總是同時發(fā)生改變則可將它們封裝在同一類中。

單一職責原則是實現(xiàn)高內(nèi)聚许帐、低耦合的指導方針,它是最簡單但又最難運用的原則毕谴,需要設(shè)計人員發(fā)現(xiàn)類的不同職責并將其分離成畦,而發(fā)現(xiàn)類的多重職責需要設(shè)計人員具有較強的分析設(shè)計能力和相關(guān)實踐經(jīng)驗距芬。

1.2 開閉原則

原文鏈接 - 面向?qū)ο笤O(shè)計原則之開閉原則

開閉原則是面向?qū)ο蟮目蓮陀迷O(shè)計的第一塊基石,它是最重要的面向?qū)ο笤O(shè)計原則循帐,定義如下

開閉原則(Open-Closed Principle, OCP):一個軟件實體應當對擴展開放框仔,對修改關(guān)閉。即軟件實體應盡量在不修改原有代碼的情況下進行擴展拄养。

在開閉原則的定義中离斩,軟件實體可以指一個軟件模塊、一個由多個類組成的局部結(jié)構(gòu)或一個獨立的類瘪匿。

總結(jié):對軟件實體的改動跛梗,最好用擴展而非修改的方式。

1.3 里氏替換原則

原文鏈接 - 面向?qū)ο笤O(shè)計原則之里氏代換原則

里氏代換原則(Liskov Substitution Principle, LSP):所有引用基類(父類)的地方必須能透明地使用其子類的對象棋弥。

里氏代換原則告訴我們在軟件中將一個基類對象替換成它的子類對象核偿,程序?qū)⒉粫a(chǎn)生任何錯誤和異常,反過來則不成立顽染,如果一個軟件實體使用的是一個子類對象的話漾岳,那么它不一定能夠使用基類對象。

里氏代換原則是實現(xiàn)開閉原則的重要方式之一粉寞,由于使用基類對象的地方都可以使用子類對象尼荆,因此在程序中盡量使用基類類型來對對象進行定義,而在運行時再確定其子類類型唧垦,用子類對象來替換父類對象捅儒。

在使用里氏代換原則時需要注意如下幾個問題:

(1)子類的所有方法必須在父類中聲明,或子類必須實現(xiàn)父類中聲明的所有方法业崖。根據(jù)里氏代換原則野芒,為了保證系統(tǒng)的擴展性,在程序中通常使用父類來進行定義双炕,如果一個方法只存在子類中狞悲,在父類中不提供相應的聲明,則無法在以父類定義的對象中使用該方法妇斤。

(2) 我們在運用里氏代換原則時摇锋,盡量把父類設(shè)計為抽象類或者接口,讓子類繼承父類或?qū)崿F(xiàn)父接口站超,并實現(xiàn)在父類中聲明的方法荸恕,運行時,子類實例替換父類實例死相,我們可以很方便地擴展系統(tǒng)的功能融求,同時無須修改原有子類的代碼,增加新的功能可以通過增加一個新的子類來實現(xiàn)算撮。里氏代換原則是開閉原則的具體實現(xiàn)手段之一生宛。

1.4 接口隔離原則

原文鏈接 - 面向?qū)ο笤O(shè)計原則之接口隔離原則

接口隔離原則(Interface Segregation Principle, ISP):使用多個專門的接口县昂,而不使用單一的總接口,即客戶端不應該依賴那些它不需要的接口陷舅。

  1. 根據(jù)接口隔離原則倒彰,當一個接口太大時,我們需要將它分割成一些更細小的接口莱睁,使用該接口的客戶端僅需知道與之相關(guān)的方法即可待讳。每一個接口應該承擔一種相對獨立的角色,不干不該干的事仰剿,該干的事都要干创淡。

  2. 接口僅僅提供客戶端需要的行為,客戶端不需要的行為則隱藏起來酥馍,應當為客戶端提供盡可能小的單獨的接口辩昆,而不要提供大的總接口。

  3. 在使用接口隔離原則時旨袒,我們需要注意控制接口的粒度汁针,接口不能太小,如果太小會導致系統(tǒng)中接口泛濫砚尽,不利于維護施无;接口也不能太大,太大的接口將違背接口隔離原則必孤,靈活性較差猾骡,使用起來很不方便。一般而言敷搪,接口中僅包含為某一類用戶定制的方法即可兴想,不應該強迫客戶依賴于那些它們不用的方法。

1.5 依賴倒置原則

原文鏈接 - 面向?qū)ο笤O(shè)計原則之依賴倒轉(zhuǎn)原則

依賴倒轉(zhuǎn)原則(Dependency Inversion Principle, DIP):抽象不應該依賴于細節(jié)赡勘,細節(jié)應當依賴于抽象嫂便。換言之,要針對接口編程闸与,而不是針對實現(xiàn)編程毙替。

如果說開閉原則是面向?qū)ο笤O(shè)計的目標的話,那么依賴倒轉(zhuǎn)原則就是面向?qū)ο笤O(shè)計的主要實現(xiàn)機制之一践樱,它是系統(tǒng)抽象化的具體實現(xiàn)厂画。

理解:高層模塊不應該依賴低層模塊,二者都應該依賴其抽象拷邢;抽象不應該依賴細節(jié)袱院;細節(jié)應該依賴抽象。

依賴倒轉(zhuǎn)原則要求我們在程序代碼中傳遞參數(shù)時或在關(guān)聯(lián)關(guān)系中,盡量引用層次高的抽象層類坑填,即使用接口和抽象類進行變量類型聲明抛人、參數(shù)類型聲明、方法返回類型聲明脐瑰,以及數(shù)據(jù)類型的轉(zhuǎn)換等,而不要用具體類來做這些事情廷臼。為了確保該原則的應用苍在,一個具體類應當只實現(xiàn)接口或抽象類中聲明過的方法,而不要給出多余的方法荠商,否則將無法調(diào)用到在子類中增加的新方法寂恬。

在引入抽象層后,系統(tǒng)將具有很好的靈活性莱没,在程序中盡量使用抽象層進行編程初肉,而將具體類寫在配置文件中,這樣一來饰躲,如果系統(tǒng)行為發(fā)生變化牙咏,只需要對抽象層進行擴展,并修改配置文件嘹裂,而無須修改原有系統(tǒng)的源代碼妄壶,在不修改的情況下來擴展系統(tǒng)的功能,滿足開閉原則的要求寄狼。

在實現(xiàn)依賴倒轉(zhuǎn)原則時丁寄,我們需要針對抽象層編程,而將具體類的對象通過依賴注入(DependencyInjection, DI)的方式注入到其他對象中泊愧,依賴注入是指當一個對象要與其他對象發(fā)生依賴關(guān)系時伊磺,通過抽象來注入所依賴的對象。常用的注入方式有三種删咱,分別是:構(gòu)造注入屑埋,設(shè)值注入(Setter注入)```和接口注入``。構(gòu)造注入是指通過構(gòu)造函數(shù)來傳入具體類的對象腋腮,設(shè)值注入是指通過Setter方法來傳入具體類的對象雀彼,而接口注入是指通過在接口中聲明的業(yè)務(wù)方法來傳入具體類的對象。這些方法在定義時使用的是抽象類型即寡,在運行時再傳入具體類型的對象徊哑,由子類對象來覆蓋父類對象。

總結(jié): 開閉原則是目標聪富,里氏代換原則是基礎(chǔ)莺丑,依賴倒轉(zhuǎn)原則是手段

1.6 迪米特法則

原文鏈接 - 面向?qū)ο笤O(shè)計原則之迪米特法則

迪米特法則(Law of Demeter, LoD):一個軟件實體應當盡可能少地與其他實體發(fā)生相互作用。

如果一個系統(tǒng)符合迪米特法則,那么當其中某一個模塊發(fā)生修改時梢莽,就會盡量少地影響其他模塊萧豆,擴展會相對容易,這是對軟件實體之間通信的限制昏名,迪米特法則要求限制軟件實體之間通信的寬度和深度涮雷。迪米特法則可降低系統(tǒng)的耦合度,使類與類之間保持松散的耦合關(guān)系轻局。

理解:一個對象對另一個對象了解得越多洪鸭,那么,它們之間的耦合性也就越強仑扑,當修改其中一個對象時览爵,對另一個對象造成的影響也就越大。

迪米特法則還有幾種定義形式镇饮,包括:不要和“陌生人”說話蜓竹、只與你的直接朋友通信等,在迪米特法則中储藐,對于一個對象俱济,其朋友包括以下幾類:

  • 1 當前對象本身(this);
  • 2 以參數(shù)形式傳入到當前對象方法中的對象邑茄;
  • 3 當前對象的成員對象姨蝴;
  • 4 如果當前對象的成員對象是一個集合,那么集合中的元素也都是朋友肺缕;
  • 5 當前對象所創(chuàng)建的對象左医。

任何一個對象,如果滿足上面的條件之一同木,就是當前對象的“朋友”浮梢,否則就是“陌生人”。在應用迪米特法則時彤路,一個對象只能與直接朋友發(fā)生交互秕硝,不要與“陌生人”發(fā)生直接交互,這樣做可以降低系統(tǒng)的耦合度洲尊,一個對象的改變不會給太多其他對象帶來影響远豺。

迪米特法則要求我們在設(shè)計系統(tǒng)時,應該盡量減少對象之間的交互坞嘀,如果兩個對象之間不必彼此直接通信躯护,那么這兩個對象就不應當發(fā)生任何直接的相互作用,如果其中的一個對象需要調(diào)用另一個對象的某一個方法的話丽涩,可以通過第三者轉(zhuǎn)發(fā)這個調(diào)用棺滞。簡言之裁蚁,就是通過引入一個合理的第三者來降低現(xiàn)有對象之間的耦合度。

在將迪米特法則運用到系統(tǒng)設(shè)計中時继准,要注意下面的幾點:

  • 在類的劃分上枉证,應當盡量創(chuàng)建松耦合的類,類之間的耦合度越低移必,就越有利于復用室谚,一個處在松耦合中的類一旦被修改,不會對關(guān)聯(lián)的類造成太大波及避凝;
  • 在類的結(jié)構(gòu)設(shè)計上舞萄,每一個類都應當盡量降低其成員變量和成員函數(shù)的訪問權(quán)
  • 限;在類的設(shè)計上管削,只要有可能,一個類型應當設(shè)計成不變類撑螺;
  • 在對其他類的引用上含思,一個對象對其他對象的引用應當降到最低。
1.7 組合/聚合復用原則(合成復用原則)

原文鏈接 - 面向?qū)ο笤O(shè)計原則之合成復用原則

合成復用原則(Composite Reuse Principle, CRP):盡量使用對象組合甘晤,而不是繼承來達到復用的目的含潘。

合成復用原則就是在一個新的對象里通過關(guān)聯(lián)關(guān)系(包括組合關(guān)系和聚合關(guān)系)來使用一些已有的對象,使之成為新對象的一部分线婚;新對象通過委派調(diào)用已有對象的方法達到復用功能的目的遏弱。簡言之:復用時要盡量使用組合/聚合關(guān)系(關(guān)聯(lián)關(guān)系),少用繼承塞弊。

在面向?qū)ο笤O(shè)計中漱逸,可以通過兩種方法在不同的環(huán)境中復用已有的設(shè)計和實現(xiàn),即通過組合/聚合關(guān)系或通過繼承游沿,但首先應該考慮使用組合/聚合饰抒,組合/聚合可以使系統(tǒng)更加靈活,降低類與類之間的耦合度诀黍,一個類的變化對其他類造成的影響相對較少袋坑;其次才考慮繼承,在使用繼承時眯勾,需要嚴格遵循里氏代換原則枣宫,有效使用繼承會有助于對問題的理解,降低復雜度吃环,而濫用繼承反而會增加系統(tǒng)構(gòu)建和維護的難度以及系統(tǒng)的復雜度也颤,因此需要慎重使用繼承復用。

優(yōu)缺點詳解

繼承
通過繼承來進行復用的主要問題在于繼承復用會破壞系統(tǒng)的封裝性模叙,因為繼承會將基類的實現(xiàn)細節(jié)暴露給子類歇拆,由于基類的內(nèi)部細節(jié)通常對子類來說是可見的,所以這種復用又稱“白箱”復用,如果基類發(fā)生改變故觅,那么子類的實現(xiàn)也不得不發(fā)生改變厂庇;從基類繼承而來的實現(xiàn)是靜態(tài)的,不可能在運行時發(fā)生改變输吏,沒有足夠的靈活性权旷;而且繼承只能在有限的環(huán)境中使用(如類沒有聲明為不能被繼承)。

組合/聚合
由于組合或聚合關(guān)系可以將已有的對象(也可稱為成員對象)納入到新對象中贯溅,使之成為新對象的一部分拄氯,因此新對象可以調(diào)用已有對象的功能,這樣做可以使得成員對象的內(nèi)部實現(xiàn)細節(jié)對于新對象不可見它浅,所以這種復用又稱為“黑箱”復用译柏,相對繼承關(guān)系而言,其耦合度相對較低姐霍,成員對象的變化對新對象的影響不大鄙麦,可以在新對象中根據(jù)實際需要有選擇性地調(diào)用成員對象的操作;合成復用可以在運行時動態(tài)進行镊折,新對象可以動態(tài)地引用與成員對象類型相同的其他對象胯府。

總結(jié):首先應該考慮使用組合/聚合,其次才考慮繼承恨胚。在實現(xiàn)復用時應該多用關(guān)聯(lián)骂因,少用繼承。


本文大部門參考了 劉偉技術(shù)博客 中關(guān)于設(shè)計模式原則的理解赃泡,非常感謝該作者寒波。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市急迂,隨后出現(xiàn)的幾起案子影所,更是在濱河造成了極大的恐慌,老刑警劉巖僚碎,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猴娩,死亡現(xiàn)場離奇詭異,居然都是意外死亡勺阐,警方通過查閱死者的電腦和手機卷中,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來渊抽,“玉大人蟆豫,你說我怎么就攤上這事±撩疲” “怎么了十减?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵栈幸,是天一觀的道長。 經(jīng)常有香客問我帮辟,道長速址,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任由驹,我火速辦了婚禮芍锚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蔓榄。我一直安慰自己并炮,他們只是感情好,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布甥郑。 她就那樣靜靜地躺著逃魄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪澜搅。 梳的紋絲不亂的頭發(fā)上嗅钻,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機與錄音店展,去河邊找鬼。 笑死秃流,一個胖子當著我的面吹牛赂蕴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播舶胀,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼概说,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了嚣伐?” 一聲冷哼從身側(cè)響起糖赔,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎轩端,沒想到半個月后放典,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡基茵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年奋构,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拱层。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡弥臼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出根灯,到底是詐尸還是另有隱情径缅,我是刑警寧澤掺栅,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站纳猪,受9級特大地震影響氧卧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜兆旬,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一假抄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧丽猬,春花似錦宿饱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至由桌,卻和暖如春为黎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背行您。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工铭乾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人娃循。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓炕檩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親捌斧。 傳聞我的和親對象是個殘疾皇子笛质,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容

  • 目錄: 設(shè)計模式六大原則(1):單一職責原則 設(shè)計模式六大原則(2):里氏替換原則 設(shè)計模式六大原則(3):依賴倒...
    加油小杜閱讀 723評論 0 1
  • 軟件開發(fā)是始于面向過程的 軟件開發(fā)是始于面向過程的,因為面向過程地解決問題更直接捞蚂,軟件本身就是一個解決問題的過程妇押;...
    侏羅紀猿閱讀 755評論 0 2
  • 前言 設(shè)計模式六大原則網(wǎng)上資料比較多比較亂,本文將網(wǎng)上的一些好的資料做一下整理姓迅,以便隨時翻閱敲霍。友情提示,設(shè)計模式雖...
    簡單的土豆閱讀 1,430評論 0 10
  • 什么是設(shè)計模式 在GoF(Gang of Four)的書籍《Design Patterns - Elements ...
    zhrowable閱讀 1,009評論 0 1
  • 我希望 每顆星星 都是一粒種子 一場春雨過后 他們從天上 落入土壤 我想 把死去的親人們 重新種回來: 姥爺是榕...
    向日葵愛呀愛太陽閱讀 214評論 0 0