iOS開發(fā)中,cocoa touch框架是一個(gè)非常穩(wěn)定和成熟的框架,這樣的一個(gè)優(yōu)秀框架,必然少不了設(shè)計(jì)模式的存在。本文將設(shè)計(jì)模式的講解過渡到iOS設(shè)計(jì)中,體會(huì)歷史沉淀下來的設(shè)計(jì)模式的精妙
1、工廠模式
- 結(jié)構(gòu)圖:
工廠模式
-
是什么:
- 提供一個(gè)類似工廠加工的方法,創(chuàng)建具體對(duì)象,返回抽象類型
- 具體生成什么類型在工廠內(nèi)部進(jìn)行判斷
- 最后抽象類型(父類)指向具體對(duì)象,作為產(chǎn)品
-
哪里好:
- 工廠方法具有面向?qū)ο蟮膬?yōu)點(diǎn),古代沒有活字印刷的時(shí)候,直接進(jìn)行雕刻,是面向過程的,復(fù)用和維護(hù)都非常困難,活字印刷是面向?qū)ο蟮模愃乒S方法,維護(hù)和復(fù)用都很方便
- 將具體產(chǎn)生什么類型隱藏起來,將產(chǎn)生什么類型交給子類決定
-
哪里有:
- NSNumber的API中,有類初始化方法,將會(huì)產(chǎn)生兩種類型,NSCFBoolean和NSCFNumber,這兩個(gè)類仍然是工廠,而不屬于具體對(duì)象,繼續(xù)往下,NSCFBoolean和NSCFNumber的intValue和boolValue方法將會(huì)生成具體的對(duì)象,NSCFBoolean和NSCFNumber就是所謂的工廠模式的體現(xiàn)
2、抽象工廠
-
結(jié)構(gòu)圖:
抽象工廠 -
是什么:
- 可以是一個(gè)接口或者一個(gè)類,有很多工廠會(huì)實(shí)現(xiàn)這個(gè)接口或者繼承這個(gè)類
- 抽象工廠模式相當(dāng)于多個(gè)工廠實(shí)現(xiàn)了統(tǒng)一接口或者繼承了同一個(gè)類
-
哪里好:
- 如果只有一種類型的工廠,那么用工廠模式即可,但是有些情況下會(huì)存在同類的多個(gè)工廠,這時(shí)候就擴(kuò)展為抽象工廠
哪里有:NSNumber調(diào)用類初始化方法后,返回的對(duì)象是NSCFBoolean和NSBoolean工廠,這兩個(gè)工廠繼承于NSNumber,擁有同樣的一些方法,例如intValue和boolValue,在NSNumber的角度看,這就是抽象工廠,同時(shí)iOS中把抽象工廠別名為“類簇”
3、裝飾者
-
結(jié)構(gòu)圖:
裝飾者 -
是什么:
- 原始的類和裝飾者接口共同實(shí)現(xiàn)一個(gè)接口(如果只有一個(gè)裝飾者類的話,那么就可以不用接口)
- 裝飾類中有一個(gè)接口類型的對(duì)象
- 裝飾類中有新的方法,內(nèi)嵌在接口的方法中
- 裝飾類對(duì)象和原始類對(duì)象都可以作為裝飾類對(duì)象的接口類型對(duì)象
-
哪里好:會(huì)思考的人可能發(fā)現(xiàn),這種模式其實(shí)可以用子類化的形式來進(jìn)行,那到底優(yōu)點(diǎn)在哪里呢
- 裝飾類不會(huì)破壞原始類的性質(zhì),同時(shí)也添加不同的特性(這點(diǎn)子類化也能做到)
- 裝飾類中的對(duì)象既可以是原始類對(duì)象,有也可以是其他裝飾類對(duì)象,這樣就能很方便的出現(xiàn)多種類型組合,而用子類化的方式去做到話,將會(huì)產(chǎn)生大量子類
- 哪里有: iOS中的范疇(Category)是一種變相的裝飾者模式,他的原理是在編譯的時(shí)候動(dòng)態(tài)為原來的類添加方法,而不是擁有一個(gè)原始類的實(shí)例,嚴(yán)格意義上不是裝飾者,但是卻和裝飾者思想很像,在需要添加的功能很少的時(shí)候可以用Category
4、責(zé)任鏈模式
-
結(jié)構(gòu)圖:
責(zé)任鏈 -
是什么:
- 責(zé)任鏈和裝飾者很像,因?yàn)樵趯?shí)現(xiàn)統(tǒng)一接口的這些類中,都有一個(gè)自己接口的對(duì)象類型
- 但是又有所不同,裝飾者是在統(tǒng)一的方法中添加新的功能,責(zé)任鏈則是都具有自己獨(dú)一無二的功能
- 通過對(duì)象與對(duì)象之間的鏈接,構(gòu)成一條完整的邏輯線
- 如同工廠里面的產(chǎn)品生產(chǎn)線,每個(gè)部門都有自己擅長(zhǎng)的部分,只做自己的部分,其他部分交給其他部門來完成
-
哪里好:
- 將提交申請(qǐng)者和申請(qǐng)?zhí)幚碚咧g的耦合解除,提交申請(qǐng)者不需要關(guān)心是誰在處理申請(qǐng)
- 處理者只需要關(guān)心自己擅長(zhǎng)的部分,如果不會(huì),則交給下一位去做
5、觀察者模式
-
結(jié)構(gòu)圖:
觀察者 -
是什么:
- 為對(duì)象之間添加一種依賴的關(guān)系,當(dāng)某一方對(duì)象的屬性發(fā)生變化的時(shí)候,另一方的對(duì)象自動(dòng)進(jìn)行相關(guān)更新操作
-
哪里好:
- 解除了相互依賴的對(duì)象之間過多的耦合,雙方對(duì)對(duì)方的了解都很少
- 當(dāng)一方對(duì)象屬性變化時(shí),另一方能自動(dòng)做出相應(yīng)的變化(這一點(diǎn)可以說是觀察者模式的核心)
-
哪里有:iOS中有兩種關(guān)于觀察者模式的實(shí)現(xiàn),一種是通知機(jī)制,一種是KVO機(jī)制,通知機(jī)制不是最原始的觀察者模式,但是卻在核心的思想上面進(jìn)行適合iOS開發(fā)的修改,KVO能夠很好詮釋觀察者模式
- 通知機(jī)制
- 使用了一個(gè)通知中心的單例來作為平臺(tái)
- 被觀察者為一個(gè)特定的類對(duì)象(NSNotification),該類的作用就是作為一種通知
- KVO
- 觀察者實(shí)現(xiàn)一個(gè)方法(update方法),如果是是一個(gè)對(duì)象要使用,則封裝在對(duì)象的.m文件中,如果是視圖控制器使用,賊在試圖控制器中實(shí)現(xiàn)就好
- 被觀察者需要添加觀察者,一般來說我們會(huì)添加self,然后在當(dāng)前控制器上實(shí)現(xiàn)方法,可能很多人都會(huì)使用這個(gè),但是卻不了解這個(gè)原理,這一步的操作實(shí)際上是將該控制器對(duì)象作為觀察者添加了,實(shí)現(xiàn)的這個(gè)方法,其實(shí)就是觀察者的update方法
- 關(guān)于怎么在屬性變化的時(shí)候通知觀察者調(diào)用update方法,這個(gè)邏輯被封裝到了KVO內(nèi)部,自己也能試著模擬
- 通知機(jī)制
6、命令模式
-
結(jié)構(gòu)圖:
命令 -
是什么:
- 對(duì)于直接調(diào)用的方法,利用一個(gè)對(duì)象,將方法封裝起來,被稱為命令
- 并通過一個(gè)類似于“服務(wù)員”的角色和調(diào)用命令的對(duì)象進(jìn)行交互
-
哪里好:命令模式從本質(zhì)上來說,其實(shí)就是將直接調(diào)用的方法封裝起來,變成一個(gè)對(duì)象,好處有這些
- 封裝起來,相當(dāng)于是一種延時(shí)操作,所以可以利用這種模式做撤銷
- 同時(shí)可以為方法設(shè)置一個(gè)隊(duì)列,具有執(zhí)行順序的隊(duì)列,在什么時(shí)候執(zhí)行也可以加以限制
-
哪里有:
- NSInvocation
-
結(jié)構(gòu)圖:
NSInvocation - NSInvocation的角色就是命令模式中的封裝方法的命令類
-
結(jié)構(gòu)圖:
- NSUndoManager
- NSUndoManager提供了撤銷機(jī)制
- NSUndoManger也是利用了NSInvocation類對(duì)象作為命令角色
- NSInvocation
7、備忘錄模式
-
結(jié)構(gòu)圖:
備忘錄 - 是什么:
- 捕獲對(duì)象內(nèi)部的狀態(tài),在對(duì)象之外封裝起來,方便恢復(fù)
-
哪里好:
- 備忘錄模式在很多場(chǎng)景都會(huì)使用,例如存檔,游戲進(jìn)度存儲(chǔ)和讀取等等
-
哪里有:
- 歸檔
- 備忘錄對(duì)象即為歸檔對(duì)象
- 被歸檔的對(duì)象為操作對(duì)象
- 文件系統(tǒng)則為備忘錄管理者
- 屬性列表序列化
- 歸檔
8、組合模式
-
結(jié)構(gòu)圖:
組合 -
是什么:
- 將同一類對(duì)象組合成樹狀結(jié)構(gòu),具有部分和整體的層次,但是部分和整體保持一致性
-
哪里好:
- 能夠保證整體和單個(gè)的一致性,對(duì)外界的接口是一致的
- 對(duì)整體的處理能夠遍歷到所有局部個(gè)體
-
哪里有:
- 在UIKit框架中,UIView的設(shè)計(jì)能夠非常明確地體現(xiàn)這種設(shè)計(jì)模式
- UIView是可以添加UIView類以及它子類的對(duì)象的
- UIView對(duì)象的渲染以及其他操作會(huì)遍歷到子類去依次進(jìn)行
-
圖示:
UIView如何體現(xiàn)組合模式
- 在UIKit框架中,UIView的設(shè)計(jì)能夠非常明確地體現(xiàn)這種設(shè)計(jì)模式
9、單例模式
-
結(jié)構(gòu)圖:
單利 -
是什么:相信單例模式是iOS開發(fā)者非常熟悉的幾個(gè)模式之一
- 保證一個(gè)類僅有一個(gè)實(shí)例
- 同時(shí)提供一個(gè)訪問該唯一實(shí)例的訪問接口
-
哪里好:
- 當(dāng)一個(gè)類只需要產(chǎn)生一個(gè)實(shí)例的時(shí)候會(huì)用到單例模式
-
哪里有:相信iOS開發(fā)者對(duì)一些存在于開發(fā)中的單例類已經(jīng)非常熟悉
- UIApplication:控制iOS應(yīng)用程序的類
- UIAccelerometer:加速器感應(yīng)的類
- NSFileManager:文件管理的類
最后,還需要推薦一篇文章,是我在前年寫的,現(xiàn)在看起來,還是蠻不錯(cuò)的一篇文章iOS單例設(shè)計(jì)模式詳細(xì)講解(單例設(shè)計(jì)模式不斷完善的過程)
10、策略模式
-
結(jié)構(gòu)圖:
策略 -
是什么:
- 定義一系列的算法,將他們封裝為對(duì)象,可以相互替換
-
哪里好:
- 策略模式的作用就是將大量的if else結(jié)構(gòu)給除去,使用對(duì)象來執(zhí)行操作
- 避免將算法的具體細(xì)節(jié)暴露給外部
-
哪里有:
- MVC模式中涵蓋了很多其他的模式,其中策略模式就是其中之一,策略模式在MVC模式中的體現(xiàn)為:控制器作為視圖的策略類,視圖在沒有控制器的情況下,顯示應(yīng)該是一樣的,但是不同的控制器將會(huì)給視圖賦予不同的數(shù)據(jù)已經(jīng)輸出模式等
11、原型模式
-
結(jié)構(gòu)圖:
原型 -
是什么:
- 為一個(gè)類添加復(fù)制操作來創(chuàng)建新的對(duì)象
-
哪里好:
- 如果一個(gè)對(duì)象是組合對(duì)象(見組合模式),那么使用原型模式來為對(duì)象創(chuàng)建克隆方法較為方便
-
哪里有:原型模式在實(shí)際開發(fā)中使用的并不是很多,但是原型模式中克隆方法就有所講究了,這里對(duì)克隆的方法簡(jiǎn)要說明一下:
- 淺復(fù)制:
- 只復(fù)制指向?qū)嶋H對(duì)象的指針,兩個(gè)指針指向的仍然是一個(gè)資源
- 淺復(fù)制
- 深復(fù)制:
- 復(fù)制指向?qū)ο蟮闹羔樢约爸羔樦赶虻馁Y源
- 深復(fù)制
- 淺復(fù)制:
具體iOS中的體現(xiàn),跳轉(zhuǎn)iOS剖析深淺復(fù)制
12、生成器模式
-
結(jié)構(gòu)圖:
生成器 -
是什么:
- 將創(chuàng)建對(duì)象的細(xì)節(jié)封裝到其他類
- 將多樣化的創(chuàng)建過程封裝起來,用戶只需要制定創(chuàng)建的類型即可
-
哪里好:
- 客戶類中的創(chuàng)建代碼不再需要大量if else進(jìn)行判斷創(chuàng)建,直接制定類型即可創(chuàng)建
- 將創(chuàng)建過程封裝起來,變得非常穩(wěn)定不易出錯(cuò)
-
和抽象工廠有什么區(qū)別:
區(qū)別
13、代理模式
-
結(jié)構(gòu)圖:
代理 -
是什么:
- 一個(gè)類委托另外一個(gè)類去做一件事情
-
哪里有:
- iOS中的協(xié)議、代理和委托對(duì)象構(gòu)成了代理模式:
- 協(xié)議:是約束代理對(duì)象需要進(jìn)行的操作
- 代理:執(zhí)行被指派的操作
- 委托:指派任務(wù)的角色
- 用UITableView來細(xì)化這種模式:
- UITableView:作為委托者,內(nèi)部擁有一個(gè)代理對(duì)象,在創(chuàng)建視圖的方法中(推測(cè)內(nèi)部實(shí)現(xiàn))會(huì)使用代理對(duì)象執(zhí)行協(xié)議中的方法
- UITableViewDelegate&UITableViewDataSource:作為協(xié)議,約束了代理對(duì)象需要實(shí)現(xiàn)的方法
- UIViewController(或者是為了系統(tǒng)瘦身自定定義的一個(gè)代理類):實(shí)現(xiàn)了協(xié)議中的方法
- iOS中的協(xié)議、代理和委托對(duì)象構(gòu)成了代理模式:
14、適配模式
-
結(jié)構(gòu)圖:
-
類適配模式:
類適配器 -
對(duì)象適配器模式:
對(duì)象適配器
-
-
是什么:
- 一個(gè)類想要調(diào)用另外一個(gè)類的方法,但是卻不兼容
- 利用適配器類包裝不兼容的方法,變?yōu)榧嫒莘椒ü┢渌愂褂?/li>
-
哪里好:
- 在方法調(diào)用不兼容的時(shí)候使用
-
哪里有:
- iOS開發(fā)中如果導(dǎo)入了某個(gè)SDK,如果SDK中有一些方法在你的APP中并不兼容,那么這個(gè)時(shí)候適配器模式就能大顯神威
- 利用協(xié)議為適配器類約定方法
- 將SDK中方法封裝到協(xié)議方法中
- 并添加上自己APP中需要進(jìn)行的處理
- iOS開發(fā)中如果導(dǎo)入了某個(gè)SDK,如果SDK中有一些方法在你的APP中并不兼容,那么這個(gè)時(shí)候適配器模式就能大顯神威
15、模板方法模式
-
結(jié)構(gòu)圖:
模板方法 -
是什么:
- 利用一個(gè)抽象類封裝基本的方法,并提供一些需要讓子類去完善的方法接口
- 在基本方法中調(diào)用這些需要讓子類完善的方法,從而達(dá)到不同的子類可以根據(jù)不同的情況實(shí)現(xiàn)不同的代碼
-
哪里有:
- UIView的drawRect方法:該方法是用于描述UIView長(zhǎng)什么樣子的,這個(gè)方法留給子類去實(shí)現(xiàn),從而實(shí)現(xiàn)不同繪制
- UIViewController的設(shè)備不同方向的方法
16、迭代器模式
-
結(jié)構(gòu)圖:
迭代器 -
是什么:
- 迭代器類中擁有需要遍歷的集合的對(duì)象,在暴露出來的方法中操作集合對(duì)象
-
哪里好:
- 如果不想暴露集合內(nèi)部的信息,那么可以使用迭代器模式,通過迭代器暴露的方法來對(duì)集合進(jìn)行訪問和操作
-
哪里有:
- NSEnumerator是iOS中的迭代器類,可以對(duì)常用的集合對(duì)象進(jìn)行訪問和操作
17、橋接模式
-
結(jié)構(gòu)圖:
橋接 -
是什么:
- 很多書上說:抽象部分和實(shí)現(xiàn)部分分離,但是我覺得這種解釋很不容易理解
- 這里給出通俗的解釋:相互關(guān)聯(lián)的類中,每個(gè)類都具有類的抽象,同時(shí)也有具體類的實(shí)現(xiàn),這種情況下,與其將兩個(gè)類體系利用繼承融合起來,還不如使用聚合/組合將兩個(gè)類體現(xiàn)關(guān)聯(lián)起來。
-
哪里好:
- 兩個(gè)類體系對(duì)外界暴露的接口都是抽象的,所以修改一個(gè)類體系的類的具體實(shí)現(xiàn)是不會(huì)對(duì)另一個(gè)類體系造成影響的
- 可以有很多種組合方法,到底是A中擁有B,還是B中擁有A,都是可以實(shí)現(xiàn)的
18、外觀模式
-
結(jié)構(gòu)圖:
外觀 -
是什么:
- 為一組具有關(guān)聯(lián)的接口提供一個(gè)統(tǒng)一的接口,簡(jiǎn)化調(diào)用
-
哪里好:
- 避免了必須知道一系列接口的調(diào)用細(xì)節(jié)才能完成功能的尷尬情況