iOS設(shè)計模式

前言

設(shè)計模式是有用的抽象化工具,用于解決工程和建筑等領(lǐng)域的設(shè)計問題。出于同樣的目的,軟件開發(fā)領(lǐng)域借用了這一概念,設(shè)計模式是一個對象或類的設(shè)計模板,用于解決特定領(lǐng)域經(jīng)常發(fā)生的問題。本篇共分8部分涉及22種設(shè)計模式:

  • 對象創(chuàng)建(1~6)
    • 原型模式
    • 簡單工廠模式
    • 工廠模式
    • 抽象工廠模式
    • 建造者(生成器)模式
    • 單例模式
  • 接口適配 (7~9)
    • 適配器模式
    • 橋接模式
    • 外觀模式
  • 對象去耦 (10~11)
    • 中介者模式
    • 觀察者模式
  • 抽象集合 (12~13)
    • 組合模式
    • 迭代器模式
  • 行為擴展 (14~16)
    • 訪問者模式
    • 裝飾者模式
    • 責(zé)任鏈模式
  • 算法封裝 (17~19)
    • 模板方法模式
    • 策略模式
    • 命令模式
  • 性能與對象訪問 (20~21)
    • 享元模式
    • 代理模式
  • 對象狀態(tài) (22)
    • 備忘錄模式
Design Partten

對象創(chuàng)建

一、原型模式

  1. 什么是原型模式?
    使用原型實例指定創(chuàng)建對象的種類,并通過復(fù)制這個對象創(chuàng)建新的對象。

原型模式其實是通過一個對象為模板創(chuàng)建另外一個可定制的對象,而且不需要知道任何的創(chuàng)建細節(jié)。

  1. 什么時候使用原型模式?

    • 需要創(chuàng)建的對象應(yīng)該獨立于其類型和創(chuàng)建方式。
    • 需要實例化的類是在運行時決定的。
    • 不想要與產(chǎn)品層次相對應(yīng)的工廠層次。
    • 不同類的實例間的差異僅是狀態(tài)的若干組合。因此復(fù)制相應(yīng)數(shù)量的原型比手工實例化更加方便。
    • 類不容易創(chuàng)建,比如每個組件可把其他組件作為子節(jié)點的組合對象。復(fù)制已有的組合對象并對副本進行修改會更加容易。
  2. 深拷貝與淺拷貝

    • 淺拷貝,指針級拷貝,拷貝出的新實例依舊指向源內(nèi)存空間,不論修改原來的實例或者拷貝出的實例,都會影響到另一個(因為指針指向同一塊內(nèi)存)。
    • 深拷貝,內(nèi)存級拷貝,會開辟新的內(nèi)存空間,修改原來的實例或者拷貝的實例,另一個不受到影響。

    iOS中默認的-copy是淺拷貝,若要深拷貝,需要遵守<NSCopying>協(xié)議,重寫-copyWithZone方法。

二、簡單工廠模式

  1. 什么是簡單工廠模式?
    簡單工廠模式(Simple Factory Pattern),又稱為靜態(tài)工廠方法(Static Factory Method)模式,在簡單工廠模式中,可以根據(jù)參數(shù)的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責(zé)創(chuàng)建其他類的實例,被創(chuàng)建的實例通常都具有共同的父類。
  2. 簡單工廠模式的優(yōu)點
    • 將對象的創(chuàng)建和對象本身業(yè)務(wù)處理分離可以降低系統(tǒng)的耦合度,使得兩者修改起來都相對容易。
    • 當(dāng)你需要什么,只需要傳入一個正確的參數(shù),就可以獲取你所需要的對象,而無須知道其創(chuàng)建細節(jié)。
    • 在調(diào)用工廠類的工廠方法時,由于工廠方法是靜態(tài)方法,使用起來很方便,可通過類名直接調(diào)用,而且只需要傳入一個簡單的參數(shù)即可,修改參數(shù)時無須修改任何源代碼。
  3. 簡單工廠模式的缺點
    • 簡單工廠模式最大的問題在于工廠類的職責(zé)相對過重,增加新的產(chǎn)品需要修改工廠類的判斷邏輯,這一點與開閉原則是相違背的。

簡單工廠模式Demo(計算器)

三、工廠模式

  1. 什么是工廠模式?
    定義創(chuàng)建對象的接口,讓子類決定實例化哪一個類。工廠方法使得一個類的實例化延遲到了子類。

  2. 什么時候使用工廠模式?

    • 編譯時無法準確預(yù)期需要創(chuàng)建對象的類。
    • 類想要其子類決定在運行時創(chuàng)建什么類型的實例。
    • 類有若干輔助類為其子類,而你想將返回哪個子類這種信息局部化。
  3. 工廠模式的優(yōu)勢
    和直接創(chuàng)建具體對象相比,使用工廠方法創(chuàng)建對象算是最佳的做法。
    工廠方法讓客戶端可以要求由工廠方法創(chuàng)建的對象擁有一組共同的行為。
    因此,向類層次結(jié)構(gòu)中引入新的具體產(chǎn)品并不需要修改客戶端代碼,因為返回的任何具體對象的接口跟客戶端一直使用的接口相同。

  4. Cocoa Touch中的工廠方法
    工廠方法在Cocoa Touch中使用極為廣泛,以NSNumber為例,它提供了很多的創(chuàng)建方法,比如-numberWithBool-numberWithInt他們傳入不同類型的參數(shù),獲得NSNumber實例。

工廠模式Demo(計算器)

四、抽象工廠

  1. 什么是抽象工廠?
    提供一個創(chuàng)建一系列相關(guān)或者相互依賴對象的接口,而無需指定他們的具體類。

    如果有多個類共有相同的行為,但實際實現(xiàn)不同,則可能需要某種抽象類型做為他們的父類,抽取其他們共同的行為到父類中。

    例如,我們知道普通的披薩餅是什么樣子,在點餐的時候能預(yù)計到端上來的是什么。當(dāng)我們說"出去吃披薩"時,這里的“披薩”其實就是一個抽象類型,定義了披薩餅應(yīng)該共同具有的特征。但是,從不同的店我們得到同一披薩餅(比如意大利披薩餅、臘腸披薩餅)的味道大不相同。因為有太多類型的披薩餅,我們簡單地將其叫做“披薩餅”以稱呼這種特定類型的食品。

    父類的類方法-getFactory僅僅只是返回具體的(合適需求的)工廠類。其子類不應(yīng)該重載這個方法。-getFactory方法根據(jù)配置返回一個具體的工廠實例。

  2. 抽象工廠和工廠模式的比較
    這兩者在很多方面都很相似,他們都用于相同的目的:創(chuàng)建對象而不讓客戶端知曉創(chuàng)建細節(jié),他們的對比如下:

抽象工廠 工廠模式
創(chuàng)建方式 對象組合創(chuàng)建抽象產(chǎn)品 類繼承創(chuàng)建抽象產(chǎn)品
創(chuàng)建種類 創(chuàng)建多系列產(chǎn)品 創(chuàng)建一種產(chǎn)品
如何擴展 修改父類的接口才支持新產(chǎn)品 子類創(chuàng)建者重載工廠方法以創(chuàng)建新的產(chǎn)品

抽象工廠Demo(地圖引擎)

五、建造者(生成器)模式

  1. 什么是建造者模式
    將一個復(fù)雜對象的構(gòu)建與他的表現(xiàn)分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表現(xiàn)。

    它可以將一個產(chǎn)品的內(nèi)部表象與產(chǎn)品的生成過程分割開來,從而可以使一個建造過程生成具有不同內(nèi)部表象的產(chǎn)品對象。
    如果我們用了建造者模式,那么用戶只需要指定需要建造的類型就可以得到他們的對象實例,而無需關(guān)心建造過程和細節(jié)。

    在此模式中,除了用戶和其所需的產(chǎn)品,還有兩個重要的角色Director(指導(dǎo)者)Builder(生成器)

    • Director知道Builder應(yīng)該建造什么,以參數(shù)向其提供缺少的信息來創(chuàng)建特定產(chǎn)品。
    • Builder是一個抽象接口,聲明了一個-build方法,該方法由ConcreBuilder實現(xiàn),以構(gòu)造實際的產(chǎn)品,ConcreBuilder有一個-getResult方法,向客戶端返回建造完畢的結(jié)果。
  2. 何時使用建造者模式

    • 需要創(chuàng)建涉及各種部件的復(fù)雜對象。創(chuàng)建對象的算法應(yīng)該獨立于部件的裝配方式。常見例子是構(gòu)建組合對象。
    • 構(gòu)建過程需要以不同的方式(比如,部件或者表現(xiàn)不同的組合)構(gòu)建對象。
  3. 建造者模式和抽象工廠的對比
    抽象工廠和建造者模式在 抽象對象創(chuàng)建方有許多相似之處,但是,二者卻大不相同。

    • 建造者模式關(guān)注的是分步驟創(chuàng)建復(fù)雜對象,很多時候,同一類型的對象可以以不同的方式創(chuàng)建。建造者模式在多步創(chuàng)建過程的最后一步返回產(chǎn)品。
    • 抽象工廠的重點在于創(chuàng)建簡單或者復(fù)雜產(chǎn)品的套件。抽象工廠立即返回產(chǎn)品。
    建造者模式 抽象工廠
    對象的復(fù)雜程度 構(gòu)建復(fù)雜對象 構(gòu)建簡單或者復(fù)雜對象
    需要的步驟 多步創(chuàng)建 單一步驟創(chuàng)建
    創(chuàng)建方式種類 多種方式創(chuàng)建 單一方式創(chuàng)建
    返回對象的時機 創(chuàng)建過程的最后一步 立即返回產(chǎn)品
    創(chuàng)建結(jié)果 專注一個特定的產(chǎn)品 強調(diào)創(chuàng)建一套產(chǎn)品
  4. 總結(jié)
    生成器模式能幫助構(gòu)建涉及部件與表現(xiàn)的各種組合的對象。沒有這一模式,知道構(gòu)建對象所需細節(jié)的Director可能會最終變成一個極其復(fù)雜的類。帶有無數(shù)用于構(gòu)建同一類的各種表現(xiàn)的內(nèi)嵌算法。而這些算法本應(yīng)該獨立于該對象的組成部分以及他們的裝配過程。

建造者模式Demo(畫卡通人)

六、單例模式

  1. 何為單例模式

    單例模式:保證一個類僅有一個實例,并且提供一個訪問它的全局訪問點。

    單例模式幾乎是設(shè)計模式中最簡單的了。它的意圖是使得類的一個對象成為系統(tǒng)中的唯一實例。要實現(xiàn)這一點,可以從客戶端對其進行實例化開始。因此,需要用一種只允許生成對象類唯一實例的機制來“阻止”所有想要生成對象的訪問。

  2. 何時使用單例模式

    • 類只能有一個實例,而且必須從一個為人熟知的訪問點對其進行訪問,(比如工廠方法)。
    • 這個唯一的實例只能通過子類化進行擴展,而且擴展的對象不會破壞客戶端代碼。
  3. Objective-C實現(xiàn)單例模式
    在OC中,單例模式的實現(xiàn)目前分為兩種:

    • 原始實現(xiàn)
      遵守<NSCopying>協(xié)議重寫-alloc方法和-copy方法,考慮線程安全。
    • GCD實現(xiàn)
      借助GCD的dispatch_once實現(xiàn)

單例模式Demo(一個嚴謹?shù)膯卫?

接口適配

七、適配器

  1. 何為適配器模式

    適配器模式,用于連接兩種不同種類的對象,使其毫無問題地協(xié)同工作。其思想比較簡單:適配器實現(xiàn)客戶端所需要的某種接口的行為,同時,它又連接到一個具有(完全)不同接口行為的對象。一邊是客戶端懂得如何使用的目標接口,另一邊是客戶端一無所知的被適配者,適配器在二者之間。它的主要作用是把被適配者的行為傳遞給管道另一端的客戶端。

    定義:將一個類的接口轉(zhuǎn)換成客戶希望的另外一個接口。Adapter模式使得原本接口不兼容而不能在一起工作的類可以一起工作了。

  2. 適配器分類

    • 類適配器
      它是通過類繼承實現(xiàn)的,而Objective-C有著協(xié)議(Protocol)這一語言特性,所以在Objective-C中,類可以實現(xiàn)協(xié)議,同時又繼承自父類,從而達到C++中多繼承的效果。
      要在OC中實現(xiàn)類適配器,首先需要有定義了客戶端要使用的一套行為的協(xié)議,然后用具體的適配器類來實現(xiàn)這個協(xié)議,適配器類同時也繼承被適配者。

    • 對象適配器
      與上面的類適配器不同,對象適配器不繼承被適配者,而是組合了一個對他的引用。

  3. 類適配器與對象適配器的比較

    類適配器 對象適配器
    只針對單一具體的Adaptee類,把Adaptee適配到target 可以適配多個Adaptee及子類
    易于重載Adaptee的行為,以為是通過直接的子類化進行的適配 難以重載,需要借助子類的對象而非Adaptee本身
    只有一個Adaptee對象,無需額外的這鎮(zhèn)間接訪問Adaptee 需要額外的指針間接訪問Adaptee并適配其行為

    Adaptee:被適配者
    Target:目標接口

  4. 何時使用適配器模式

    • 已有類的接口與需求不匹配
    • 想要一個可復(fù)用的類,該類能夠同可能帶有不兼容接口的其他類協(xié)作。
    • 需要適配一個類的幾個不同子類,可是讓每一個子類去子類化一個類適配又不現(xiàn)實,那么可以使用對象適配器(委托)來適配其父類的接口。

八、橋接模式

  1. 何為橋接模式?
    將抽象部分與它的實現(xiàn)部分分離,使它們都可以獨立地變化。

    所謂抽象與它的實現(xiàn)分離,這并不是說,讓抽象類與其派生類分離,因為這沒有任何意義。實現(xiàn)指的是抽象類和它的派生類用來實現(xiàn)自己的對象。

    實現(xiàn)系統(tǒng)時可能有多角度分類,每一種分類都有可能變化,那么就把這種多角度分離出來,讓他們獨立變化,減少他們之間的耦合。

  2. 合成/聚合復(fù)用原則

    • 繼承的弊端
      對象的繼承關(guān)系在編譯時就已經(jīng)定好了,所以無法在運行時改變從父類繼承的實現(xiàn)。子類的實現(xiàn)與其父類有著非常緊密的依賴關(guān)系,以至于父類實現(xiàn)中任何變化必然會導(dǎo)致子類發(fā)生變化。當(dāng)需要復(fù)用子類時,如果繼承下來的實現(xiàn)不適合新的問題,則父類必須重寫或者被其他更適合的類替換。這種依賴關(guān)系限制了靈活性并最終限制了復(fù)用性。

    • 合成/聚合復(fù)用原則
      合成(也叫做組合,Composition)和聚合(Aggregation)都是關(guān)聯(lián)的特殊種類。聚合表示一種弱的“擁有“關(guān)系,體現(xiàn)的是A對象可以包含B對象,但B對象不是A對象的一部分;合成則是一種強的”擁有“關(guān)系,體現(xiàn)了嚴格的部分和整體的關(guān)系,部分和整體的生命周期一樣。

      比如:大雁有兩個翅膀,翅膀與大雁是部分和整體的關(guān)系,并且他們的生命周期相同,于是大雁和翅膀就是合成關(guān)系。大雁是群居動物,每只大雁都屬于一個雁群,一個雁群可以有多只大雁,所以,大雁和雁群是聚合關(guān)系。

    優(yōu)先使用對象的組合/聚合將有助于保持每個類被封裝,并集中在單個任務(wù)上。這樣類和類繼承層次會保持較小規(guī)模,并且不太可能增長為不可控制的龐然大物。

  3. 何時使用橋接模式

    • 不想在抽象與實現(xiàn)之間形成固定的綁定關(guān)系(這樣可以在運行時按需切換實現(xiàn))
    • 抽象及其實現(xiàn)都應(yīng)可以通過子類化獨立擴展。
    • 對抽象的實現(xiàn)進行修改不應(yīng)該影響客戶端代碼。
    • 如果每個實現(xiàn)需要額外的子類以細化抽象,則說明有必要把他們分成兩個部分。
    • 想在帶有不同抽象接口的多個對象之間共享一個實現(xiàn)。

橋接模式Demo(手機軟件系統(tǒng))

九、外觀模式

  1. 何為外觀模式
    定義:為系統(tǒng)中的一組接口提供一個統(tǒng)一的接口,外觀定義一個高層接口,讓子系統(tǒng)更易于使用。

    外觀模式為子系統(tǒng)中一組不同的接口提供一個統(tǒng)一的接口。外觀定義了上層接口,通過降低復(fù)雜度和隱藏子系統(tǒng)之間的通信及依存關(guān)系,讓子系統(tǒng)更易于使用。

  2. 何時使用外觀模式

    • 子系統(tǒng)正在逐漸變得復(fù)雜。應(yīng)用模式的過程中演化出許多類。可以使用外觀模式為這些子系統(tǒng)類提供一個更簡單的接口。
    • 可以使用外觀對子系統(tǒng)進行分層。每個子系統(tǒng)級別有一個外觀作為入口點。讓他們通過其外觀進行通信,可以簡化他們的依賴關(guān)系。
  3. 總結(jié)
    當(dāng)程序逐漸變大變復(fù)雜的時候,會有越來越多小型的類從設(shè)計和應(yīng)用模式中演化出來。如果沒有一種簡化的方式來使用這些類,客戶端代碼會變得越來越復(fù)雜和難以理解,而且難以維護,外觀模式有助于提供一中更為簡單的方法來使用子系統(tǒng)中的這些類。處理這些子系統(tǒng)的默認行為,可能只是定義在外觀中的簡單方法,而不必直接使用這些類。

外觀模式Demo(乘客乘車案例)

對象去耦

十、中介者模式

  1. 何為中介者模式
    定義:用一個對象來封裝一系列對象的交互方式。中介者使各個對象不需要顯示地相互引用,從而使其耦合松散,而且可以獨立地改變它們之間的交互

    面向?qū)ο蟮脑O(shè)計鼓勵把行為分散到不同的對象中,這種分散可能導(dǎo)致對象之間的相互關(guān)聯(lián)。在最糟糕的情況下,所有對象都彼此之間了解和相互操作。

    雖然把行為分散到不同對象增強了可復(fù)用性,但還是增加的相互關(guān)聯(lián)有減少了獲得的益處。增加的關(guān)聯(lián)使得獨享很難或者不能在不依賴其他對象的情況下工作。應(yīng)用程序的整體行為可能難以改動,因為他分布于許多對象。

    中介者模式用于解決此類問題,它定義了一個集中的場所,對象之間的交互可以在一個中介者對象中處理,其他對象不必彼此交互,因此減少了他們之間的依存關(guān)系。

  2. 何時使用中介者模式

  • 對象之間的交互雖然定義明確但是非常復(fù)雜,導(dǎo)致一組對象彼此相互依賴而且難以理解。
  • 因為對象引用了許多其他對象并且與其通訊,導(dǎo)致對象難以復(fù)用。
  • 想要定制一個分布在多個類中的邏輯或行為,又不想生成太多子類。
  1. 中介者模式的優(yōu)缺點
    中介者模式很容易在系統(tǒng)中使用,也很容易誤用。當(dāng)系統(tǒng)出現(xiàn)了“多對多”交互復(fù)雜的對象群時,不要急于使用中介者模式,而要先反思系統(tǒng)的設(shè)計是否合理。

    • 優(yōu)點:
      1、中介者的存在,減少了各個具體類的耦合度,使各個具體類和中介者可以獨立地改變和復(fù)用;

      2、由于把對象如何協(xié)作進行了抽象,將中介者作為一個獨立的概念并將其封裝在一個對象中,這樣關(guān)注的對象就從對象各個本身的行為轉(zhuǎn)移到了他們之間的交互上來,也就是站在一個更宏觀的角度去看待系統(tǒng)。

    • 缺點:
      由于中介者控制了集中化,于是把交互復(fù)雜性變?yōu)榱酥薪檎叩膹?fù)雜性,這就使得中介者會變得比任何一個具體類都復(fù)雜。

  2. 總結(jié)
    中介者模式的應(yīng)用十分廣泛,組件化應(yīng)該算是最貼切的中介者模式的應(yīng)用場景了,各個組件,獨立開發(fā),維護,組件之間使用中間件進行通訊。詳見:iOS 一個輕量級的組件化思路

    雖然對于處理系統(tǒng)的行為分散于不同對象并且對象相互依存的情況,中介者模式非常有用,但是應(yīng)該注意避免讓中介者類過于龐大而難以維護。如果已經(jīng)如此了,可以考慮使用另外的設(shè)計模式把它分解。

中介者模式Demo(同事對話)

十一、觀察者模式

  1. 何為觀察者模式
    定義:定義對象間的一種一對多的依賴關(guān)系,當(dāng)一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并且被自動更新

    觀察者模式也叫做發(fā)布——訂閱模式。Observer從Subject訂閱通知。ConcreteObserver實現(xiàn)抽象Observer并重載其update方法。一旦Subject的實例需要通知Observer任何的變更,Subject會發(fā)送update消息來通知存儲在內(nèi)部列表中所有注冊的Observer。在ConcreteObserver的update方法的實際實現(xiàn)中,Subject的內(nèi)部狀態(tài)可被取得并在以后進行處理。

  2. 何時使用觀察者模式

    • 有兩種抽象類型相互依賴。將它們封裝在各自的對象中,就可以對它們單獨進行改變和復(fù)用。
    • 對一個對象的改變需要同時改變其他對象,而不知道具體有多少對象有待改變。
    • 一個對象必須通知其他對象,而它又不需要知道其他對象是什么。
  3. Cocoa Touch框架中的觀察者模式

    • 通知
      Cocoa Touch框架中使用NSNotificationCenter和NSNotification對象實現(xiàn)了一對多的發(fā)布——訂閱模式,他們允許主題與觀察者以一種松耦合的方式通信。兩者在通信時對另外一方無需多少了解。

    • 鍵—值觀察
      Cocoa提供了另外一種稱為鍵-值觀察的機制,對象之間可以通過它得到其他對象特定的變更通知。這種機制在MVC(Model-View-Controller)模式的場景中尤其重要,它讓視圖對象可以經(jīng)由控制器層觀察模型對象的變更。

      通知 鍵-值觀察
      一個中心對象為所有觀察者提供變更通知 被觀察的對象直接向觀 察者發(fā)送通知
      主要從廣義上關(guān)注程序事件 綁定于特定對象屬性的值

抽象集合

十二、組合模式

  1. 什么是組合模式
    定義:將對象組合成樹形結(jié)構(gòu)以表示“部分—整體”的層次結(jié)構(gòu)。組合模式使得用戶對單個對象和組合對象的使用具有一致性。

    組合模式讓我們可以把相同基類型(base type)的對象組合到樹狀結(jié)構(gòu)中,其中父節(jié)點包含同類型的子節(jié)點。換句話說,這種樹狀結(jié)構(gòu)形成"部分-整體"的層次結(jié)構(gòu)。

    樹形結(jié)構(gòu)是既包含對象的組合(容器)又包含作為葉節(jié)點(基元)的單個對象對的一種層次結(jié)構(gòu)。每個組合體包含的節(jié)點可以是葉節(jié)點也可以是其他組合體。這種關(guān)系在這個層次結(jié)構(gòu)中遞歸重復(fù)。客戶端對組合結(jié)點和葉節(jié)點擁有相同的操作,客戶端在使用時可以忽略他們之間的差別。

  2. 何時使用組合模式

    • 想獲得對象抽象的樹形結(jié)構(gòu)(部分-整體層次結(jié)構(gòu))。
    • 想讓客戶端統(tǒng)一處理組合結(jié)構(gòu)中的所有對象。
  3. 透明方式與安全方式

    • 透明方式
      在葉節(jié)點中也有-add-remove方法,然而葉節(jié)點上不需要這些行為;這樣做的目的是為了讓他們完全相同的接口,調(diào)用方完全用處理這種邏輯,這就是透明方式。

    • 安全方式
      如果不希望葉節(jié)點上存在上面的方法,那么在最基本結(jié)構(gòu)(Component)中就不聲明-add-remove方法,而是另外在聲明一個結(jié)構(gòu)(Composite)用來管理子類對象的方法,這樣就能避免透明代理出現(xiàn)的問題,但同時,由于不夠透明,所以樹葉和樹枝擁有不同的接口,客戶端的調(diào)用需要做相應(yīng)的判斷,給調(diào)用方帶來了不便。

    兩種方式?jīng)]有絕對的優(yōu)劣,看個人的理解和取舍(類比簡單工廠和工廠模式)。

組合模式Demo(公司組織架構(gòu)案例)

十三、迭代器模式

  1. 何為迭代器模式
    定義:提供一種方法順序訪問一個聚合對象中的各個元素,而又不需要暴露獨享的內(nèi)部表示。

    迭代器提供一種順序訪問聚合對象(集合)中元素的方法,而無需暴露結(jié)構(gòu)的底層表示和細節(jié)。遍歷集合中元素的職能從集合本身轉(zhuǎn)移到迭代器對象。迭代器定義了一個用于訪問集合元素并記錄當(dāng)前元素的接口。不同迭代器可以執(zhí)行不同的遍歷策略。

  2. 何時使用迭代器模式

    • 需要訪問組合對象的內(nèi)容,而又不暴露內(nèi)部表示。
    • 需要通過多種方式遍歷組合對象。
    • 需要提供一個統(tǒng)一接口,用來遍歷各種類型的組合對象。
  3. Cocoa Touch中的迭代器模式

    • NSEnumerator
      從iOS2.0開始,可以使用NSEnumerator來枚舉NSArray、NSDictionary、NSSet對象中的元素。
    • 基于block的枚舉
      在iOS4中引入了基于塊的枚舉(Block-Based Enumeratoration)
    • 快速枚舉(for-in)
    • 內(nèi)部枚舉
      NSArry有個實例方法-makeObjectsPerformSelector:,它允許客戶端向數(shù)組中每個元素發(fā)送一個消息,讓其每個元素執(zhí)行指定的方法。

迭代器模式Demo(乘客買票案例)

行為擴展

十四、訪問者模式

  1. 何為訪問者模式
    定義:表示一個作用于某對象結(jié)構(gòu)中的各元素的操作。它使你可以在不改變各元素類的前提下定義作用于這些元素的新操作。

  2. 何時使用訪問者模式

    • 一個復(fù)雜的對象結(jié)構(gòu)包含很多其他對象,他們有不同的接口,這個對象的實施依賴于其具體類型的操作。
    • 需要對一個組合結(jié)構(gòu)體中的對象進行很多不相關(guān)的操作,但是不想讓這些操作“污染”這些對象的類,可以將相關(guān)的操作集中起來,定義在一個訪問者類中,并在需要在訪問者中定義的操作時使用它。
    • 定義復(fù)雜結(jié)構(gòu)的類很少修改,單經(jīng)常需要向其添加新的操作。
  3. 總結(jié)
    訪問者模式是擴展組合結(jié)構(gòu)功能的一種強有力的方式。如果組合結(jié)構(gòu)具有精心設(shè)計的基本操作,而且結(jié)構(gòu)相對穩(wěn)定就可以使用訪問者模式。

訪問者模式Demo(男人女人案例)

十五、裝飾者模式

  1. 何為裝飾著模式
    裝飾者模式:動態(tài)地給一個對象添加一些額外的職責(zé)。就擴展功能來說,裝飾者模式相比生成子類更加靈活。

    Component是定義一個對象接口,可以給這些對象動態(tài)地添加職責(zé)。ConcreteComponent是定義了一個具體的對象,也可以給這個對象添加一些職責(zé)。Decorator,裝飾者抽象類,繼承了Component,從外類來擴展Component類的功能,但對于COmponent來說,是無需知道Decorator的存在的。至于ConcreteDecorator就是具體的裝飾對象,起到給Component添加職責(zé)的功能。

    在日常開發(fā)過程中,應(yīng)該減少類繼承的使用,過多地使用類的繼承會導(dǎo)致類數(shù)目過于龐大而變得難以維護,而使用組合可以讓我們的系統(tǒng)更具彈性,更加容易修改和擴展。

  2. 何時使用裝飾者模式

  • 想要在不影響其他對象的情況下,以動態(tài),透明的方式給單個對象添加職責(zé)。
  • 想要擴展一個類的行為,卻做不到。類定義可能被隱藏,無法進行子類化;或者,對類的每個行為的擴展,為支持各種功能組合,將產(chǎn)生大量的子類。
  • 對類的職責(zé)的擴展是可選的。
  1. 改變對象的“外表”和“內(nèi)容”

    "外表"變更(裝飾者) “內(nèi)容”變更(策略)
    從外部變更 從內(nèi)部變更
    每個節(jié)點不知道變更 每個節(jié)點知道一組預(yù)定義的變更方式

裝飾者模式Demo(給圖片加濾鏡)

十六、責(zé)任鏈模式

  1. 何為責(zé)任鏈模式

    定義:使多個對象都有機會處理請求,從而避免請求的發(fā)送者和接受者之間發(fā)生耦合。此模式將這些對象連城一天鏈,并且沿這條鏈傳遞請求,直到一個對象處理它為止。

    使用責(zé)任鏈模式可以隨意地增加或修改處理一個請求的結(jié)構(gòu),增強了對對象指派職責(zé)的靈活性。但是可能一個請求到了責(zé)任鏈的末端都得不到處理,或者因為沒有正確地配置而得不到處理,需要考慮全面。

  2. 何時使用責(zé)任鏈模式

    • 有多個對象可以處理請求,而處理程序只有在運行時才能確定。
    • 向一組對象發(fā)出請求,而不想顯示指定處理請求的特定處理程序。
  3. 總結(jié)

    責(zé)任鏈模式能很好地解決大量分支判斷,有效降低了客戶端調(diào)用的邏輯復(fù)雜度。以上的3個設(shè)計模式,都是在擴展對象行為的同時,對對象進行最少修改甚至不修改。對越來越復(fù)雜的系統(tǒng)擴展具有極大的借鑒意義。

責(zé)任鏈模式Demo(加薪案例)

算法封裝

十七、模板方法模式

  1. 何為模板方法模式

    定義:定義一個操作中的算法骨架,而將一些步驟延遲到子類中。模板方法使子類可以重新定義算法的某些y特定步驟而不改變改算法的結(jié)構(gòu)。

    其基本思想是在抽象類的一個方法中定義“標準”算法。這個方法的實現(xiàn)由子類重載實現(xiàn)。這個方法被稱為“模板”,因為方法定義的算法缺少一些特定的操作。子類重載基本操作以提供獨特操作供模板方法使用。

  2. 何時使用模板方法模式

    • 需要一次性實現(xiàn)算法的不變部分,并將可變的行為留給子類實現(xiàn)。
    • 子類的共同行為應(yīng)該被提取出來,放到公共類中, 以避免代碼重復(fù)。現(xiàn)有代碼的差別應(yīng)該被分離為新的操作。然后用一個調(diào)用這些新操作的模板方法來替換這些不同的代碼。
    • 需要控制子類的擴展,可以定義一個在特定點調(diào)用“鉤子(hook)”操作的模板方法。子類可以通過對鉤子的操作實現(xiàn)在這些點擴展功能。
  3. 模板方法 vs 適配器

模板方法 適配器(委托)模式
父類定義一個一般算法,但缺少某些特定/可選的信息或者算法,它通過這些缺少的信息或算法起到一個算法的“食譜”作用 適配器與預(yù)先定好的委托接口一起定義一個特定的算法
缺少的信息有子類通過繼承實現(xiàn) 特定算法由任何對象通過組合來提供

模板方法模式Demo(制作多種三明治)

十八、策略模式

  1. 何為策略模式
    策略模式定義了算法家族,分別封裝起來,讓他們之間可以相互替換,此模式讓算法的變化不會影響到使用算法的客戶端

    策略模式中的一個關(guān)鍵角色是策略類,它為所有支持的相關(guān)算法聲明了一個共同接口。另外,還有使用策略接口來實現(xiàn)先關(guān)算法的具體策略類。場景(Context)類的對象配置有一個具體策略對象的實例,場景對象使用策略接口調(diào)用由具體策略類定義的算法。

  2. 何時使用策略模式

    • 一個類在其操作中使用多個條件語句來定義許多行為。我們可以把相關(guān)的條件分支移到他們自己的策略類中。
    • 需要算法的各種變體。
    • 需要把復(fù)雜的、與算法相關(guān)的數(shù)據(jù)結(jié)構(gòu)暴露給客戶端。
  3. MVC中的策略模式
    模型-視圖-視圖控制器(MVC)模式中,控制器決定視圖對模型數(shù)據(jù)的顯示內(nèi)容和時機。視圖本身知道如何繪圖,但需要控制器告訴他要顯示的內(nèi)容。一個視圖如果與不同的控制器合作,數(shù)據(jù)的輸出格式可能一樣,但數(shù)據(jù)的類型和格式可能隨不同控制器的不同輸出而不同。因此,這種情況下的控制器是視圖的策略。控制器與視圖之間是一種基于策略模式的關(guān)系。

  4. 總結(jié)
    策略模式和裝飾者模式有些類似。裝飾器從外部擴展對象的行為,而各種策略則被封裝在對象之中。所以說裝飾器改變對象的“外表”而策略改變對象的“內(nèi)容”。

策略模式Demo(商場打折案例)

十九、命令模式

  1. 何為命令模式

    命令對象封裝了如何對目標執(zhí)行指令的信息,因此,客戶端或調(diào)用者不必了解目標的任何細節(jié),卻仍可以對它執(zhí)行任何已知的操作。通過吧請求封裝成對象,客戶端可以把它參數(shù)化并置入隊列或者日志中,也能支持撤銷的操作。命令對象將一個或多個動作綁定到特定的接收器。命令模式消除了作為對象的動作和執(zhí)行它的接收器之間的綁定。

    定義:將請求封裝為一個對象,從而可用不同的請求對客戶端進行參數(shù)化,隊請求排隊或記錄請求日志,以支持可撤銷操作。命令模式把請求一個操作的對象與知道怎么執(zhí)行一個操作的對象分割開

  2. 何時使用命令模式

    • 想讓應(yīng)用程序支持撤銷和恢復(fù)。
    • 想用對象參數(shù)化一個動作以執(zhí)行操作,并用不同的命令對象來代替回調(diào)函數(shù)。
    • 想要在不同時刻對請求進行指定、排列和執(zhí)行。
    • 想記錄修改日志,這樣在系統(tǒng)故障時,這些修改刻在后來重做一遍。
    • 想讓系統(tǒng)支持事務(wù),事務(wù)封裝了對數(shù)據(jù)的一些列修改。事務(wù)可以建模為命令對象。
  3. 命令模式的優(yōu)點

    1. 比較容易地設(shè)計一個命令隊列(waiter的commandList數(shù)組)
    2. 在需要的情況下,可以很容易地將命令記錄日志(在Waiter的setOrder記錄)
    3. 允許接收方命令的一方?jīng)Q定是否否決該命令(Cooker類可以通知Waiter無貨源)
    4. 可以對請求進行撤銷、修改和重做(可以修改命令的數(shù)量)
    5. 由于新加的具體命令類不影響其他類,因此增加新的具體命令類很容易

命令模式Demo(燒烤店的訂單操作)

性能與對象訪問

二十、享元模式

  1. 何為享元模式

    定義:運用共享技術(shù)有效地支持大量細粒度的對象

    實現(xiàn)享元模式需要兩個關(guān)鍵的組件,通常是可共享的享元對象和保存他們的池。某種中央對象維護這個池,并從它返回適當(dāng)?shù)膶ο髮嵗9S是這一角色的理想候選,它通過一個工廠方法返回各種類型的具體享元對象。

    享元模式可以避免大量非常相似類的開銷。在程序設(shè)計中,有時需要生成大量細粒度的類實例來表示數(shù)據(jù)。如果能發(fā)現(xiàn)這些實例除了幾個參數(shù)外基本相同,有時能夠大幅度地減少需要實例化類的數(shù)量。如果能把那些參數(shù)移到類實例的外面,在方法調(diào)用時將他們傳遞進來,就可以通過共享大幅度地減少實例的數(shù)目。

  2. 何時使用享元模式

    • 應(yīng)用程序使用很多對象
    • 在內(nèi)存中保存對象會影響性能
    • 對象的多數(shù)特有狀態(tài)可以放到外部而輕量化
    • 移除了外在狀態(tài)后,可以用較少的共享對象替換原來的那組對象
    • 應(yīng)用程序不依賴對象標識,因為共享對象不能提供唯一標識

二十一、代理模式

  1. 何為代理模式

    定義:為其他對象提供一種代理以控制對這個對象的訪問。

    代理模式的思想是使用一個基本跟實體對象行為相同的代理,客戶端可以”透明地“使用代理,即不必知道所面對的只是一個代理而不是實體對象。在iOS中,使用代理來解耦合。

    使用代理把View層的事件傳遞到Controller中

    把tableView的delegate和dataSource實現(xiàn)到一個單獨的Model或者ViewModel中

  2. 代理的分類

    • 遠程代理(remote proxy)
      為位于不同地址空間或者網(wǎng)絡(luò)上的對象提供本地代表
    • 虛擬代理(virtual proxy)
      需要根據(jù)需要創(chuàng)建重型對象
    • 保護代理(protection proxy)
      根據(jù)訪問權(quán)限控制對原對象的訪問
    • 智能引用代理(samrt-reference proxy)
      通過對真正對象的引用進行技術(shù)來管理內(nèi)存,也用于鎖定真正對象,讓其他對象不能對其進行修改。

八、對象狀態(tài)

二十二、備忘錄模式

  1. 何為備忘錄模式

    定義:在不破壞封裝性的前提下,捕捉一個對象的內(nèi)部狀態(tài),并在改對象之外保存這個狀態(tài)。這樣以后就可以將該對象恢復(fù)到原先保存的狀態(tài)。

    備忘錄模式有是三個角色:原發(fā)器(originator)、備忘錄(memento)、 管理者(caretaker)

    • 原發(fā)器(originator)
      負責(zé)創(chuàng)建一個備忘錄Memento,用來記錄當(dāng)前時刻的內(nèi)部狀態(tài),并可使用備忘錄恢復(fù)內(nèi)部狀態(tài)。originator可根據(jù)需要決定Memento存儲originator的內(nèi)部狀態(tài)
    • 備忘錄(memento)
      負責(zé)存儲originator對象的內(nèi)部狀態(tài),并防止originator以外的對象訪問備忘錄。
    • 管理者(caretaker)
      負責(zé)保存好備忘錄Memento,不能對備忘錄的內(nèi)容進行檢查或者修改。
  2. 合適使用備忘錄模式

    • 需要保存一個對象(或某部分)在某一時刻的狀態(tài),提供以后恢復(fù)到這個時刻的狀態(tài)。
    • 用于獲取狀態(tài)的接口會暴露實現(xiàn)的細節(jié),需要對外隱藏實現(xiàn)細節(jié)。

備忘錄模式Demo(游戲進度保存于恢復(fù))

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 設(shè)計模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計經(jīng)驗的總結(jié)。使用設(shè)...
    于先笙閱讀 512評論 1 3
  • 設(shè)計模式匯總 一、基礎(chǔ)知識 1. 設(shè)計模式概述 定義:設(shè)計模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 3,970評論 1 15
  • 小白程序員只能看懂源代碼,而大神程序員能看懂文檔。 設(shè)計模式:為解決特定場景的問題而定制的解決方案。設(shè)計原則:構(gòu)建...
    印林泉閱讀 889評論 0 8
  • 鏈接:https://github.com/WiKi123/DesignPattern作者: WiKi123(gi...
    樹懶啊樹懶閱讀 3,621評論 0 2
  • 對象創(chuàng)建,就是我們在創(chuàng)建對象時可能會用到的設(shè)計模式,這邊要根據(jù)自己的需求去選擇。對象創(chuàng)建有以下幾種設(shè)計模式:① 原...
    WellsCai閱讀 1,188評論 0 5