iOS 設(shè)計模式

? ? Design Pattern 設(shè)計模式是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類的、代碼設(shè)計經(jīng)驗的總結(jié)。設(shè)計模式的目的是增強代碼的可重用性、可靠性,使代碼便于他人閱讀和理解。

? ? 目前在iOS 開發(fā)中常用的設(shè)計模式是:MVC模式、MVVM模式、單例模式、代理模式、觀察者模式、策略模式、工廠模式。

1.MVC

? ? Model View Controller (MVC)是 Xerox PARC 在 20 世紀(jì) 80 年代為編程語言 Smalltalk-80 發(fā)明的一種軟件設(shè)計模式,是蘋果推薦的一個用來組織代碼,構(gòu)建iOS App的標(biāo)準(zhǔn)模式。在MVC下,所有的對象被歸類為Model、View和Controller。Model負(fù)責(zé)持有數(shù)據(jù),View用于顯示與用戶交互的界面,而Model和View之間的交互經(jīng)由ViewController進(jìn)行調(diào)解。


斯坦福白老頭的經(jīng)典圖

? ? (1)Model

? ? ? ?Model(模型對象)持有并封裝應(yīng)用數(shù)據(jù),定義操控和處理該數(shù)據(jù)的邏輯和運算。用戶在視圖層中所進(jìn)行的創(chuàng)建或修改數(shù)據(jù)的操作,通過控制器對象傳達(dá)出去,最終會創(chuàng)建或更新模型對象。模型對象更改時,它通知控制器對象,控制器對象更新相應(yīng)的視圖對象。

? ? (2)View

? ? ? ?View(視圖對象)是應(yīng)用程序向用戶直接呈現(xiàn)和并向用戶作出響應(yīng)的可視對象。其主要目的就是顯示模型對象的數(shù)據(jù),使數(shù)據(jù)可被編輯。在以往的開發(fā)中,視圖對象通常與模型對象分離。

? ? (3)Controller

? ? ? ?Controller(控制器對象)在視圖對象和模型對象之間充當(dāng)媒介,是同步管道程序。視圖對象獲悉模型對象的更改,反之亦然??刂破鲗ο鬄閼?yīng)用程序執(zhí)行設(shè)置和協(xié)調(diào)任務(wù),管理其他對象的生命周期。控制器對象捕獲用戶在視圖對象上的操作,創(chuàng)建或更改數(shù)據(jù)并傳達(dá)給模型對象。模型對象更改時,一個控制器對象會將新的模型數(shù)據(jù)傳達(dá)給視圖對象,以便視圖對象及時更新顯示的數(shù)據(jù)。

? ? MVC 在現(xiàn)實應(yīng)用中的不足:

? ? (1)控制器對象體積龐大

? ? ? ?受限于自身運行的平臺終端,移動端不能夠像 PC 端一樣處理大量的復(fù)雜業(yè)務(wù)場景,而傳統(tǒng)App 中存在的模型數(shù)據(jù)較為簡單,不會涉及到復(fù)雜的邏輯處理。傳統(tǒng)的 Model 數(shù)據(jù)主要來源于網(wǎng)絡(luò),在移動端通過網(wǎng)絡(luò)獲取到這些數(shù)據(jù)后直接顯示在界面上。隨著移動端平臺業(yè)務(wù)發(fā)展,移動端愈發(fā)的要自行處理一部分邏輯計算操作,在傳統(tǒng)App中都是由控制器進(jìn)行處理,隨著業(yè)務(wù)場景的擴(kuò)展,控制器存在的處理代碼越來越多,最終導(dǎo)致其變成了難以維護(hù)的垃圾箱。

? ? (2)視圖對象參與邏輯處理

? ? ? ?視圖對象通常是 UIKit 控件或者編碼定義的 UIKit 控件的集合,在處理實際處理中我們往往會讓視圖對對象對所要展示的數(shù)據(jù)對象的數(shù)據(jù)進(jìn)行一些邏輯處理,再進(jìn)行顯示。業(yè)務(wù)邏輯很明顯不歸入 view,視圖本身沒有任何業(yè)務(wù)。View 不應(yīng)該直接引用 Model,并且僅僅通過 IBAction 事件引用 controller。

? ? (3)Model與Controller的體積反差

? ? ? ?早期的 Model 數(shù)據(jù)對象普遍只定義了一些屬性,在Model類的實現(xiàn)文件中基本上看不到復(fù)雜的業(yè)務(wù)處理和對象的構(gòu)造,在這種叫小體積下的數(shù)據(jù)對象與厚重的控制器對象形成反差,這一度讓人不禁對現(xiàn)有的開發(fā)設(shè)計構(gòu)思有所懷疑。

? ? (4)不利于單元測試

? ? ? ? 控制器對象整合了視圖處理邏輯和業(yè)務(wù)邏輯,在進(jìn)行單元測試時不得不面對艱難的分離任務(wù),極大的影響整個開發(fā)的效率。

2.MVVM

? ? ? ? 作為構(gòu)建iOS App的標(biāo)準(zhǔn)模式,我們已在前文中列舉出了MVC幾個最突出的問題:控制器對象體積龐大、視圖對象參與邏輯處理、Model與Controller的體積反差和不利于單元測試。那么,對于一個較傳統(tǒng)App存在更復(fù)雜的視圖交互和邏輯處理的應(yīng)用開發(fā)時,選擇代碼耦合性較低且便于維護(hù)的設(shè)計模式便是我在這里介紹MVVM的目的。

? ? ? ? MVVM是從MVC引申出來以分離視圖對象和數(shù)據(jù)對象為主要目的架構(gòu)模式。是由微軟帶來的WPF與MVP在應(yīng)用結(jié)合的實踐中發(fā)展而來,用以應(yīng)對對客戶日益復(fù)雜的需求變化。

????????在基本概念上,MVVM與MVC最大的區(qū)別是設(shè)立ViewModel用于專門存放業(yè)務(wù)邏輯的代碼,進(jìn)一步加強視圖對象和業(yè)務(wù)邏輯的分離。通過引入視圖模型這樣的新組建,為控制器對象進(jìn)行減肥、降低代碼的耦合性并為單元測試提供了可能。

????????ViewModel(視圖模型)?容納了應(yīng)用程序的顯示邏輯,不僅僅包含顯示的數(shù)據(jù)和可見屬性,它還實現(xiàn)了數(shù)據(jù)對象和視圖對象交互的方法,協(xié)助控制器對象對界面控件的使用。


? ? ? ? 上圖展示了在MVVM設(shè)計模式下的邏輯關(guān)系,與上文MVC的圖片相比較可以幫助我們了解MVVM的本質(zhì)是什么。MVVM是一個升級版本的MVC。我們將原本MVC中的View和Controlle的部分邏輯轉(zhuǎn)而交由一個叫做ViewModel的對象來負(fù)責(zé)處理。它聽起來很復(fù)雜,但它本質(zhì)上是一個新版本的MVC。

? ? ? ? 到這里我已經(jīng)簡單介紹了MVVM以及它和MVC不得不說的關(guān)系,當(dāng)然我不是在慫恿開發(fā)者放棄MVC轉(zhuǎn)而都采用MVVM,畢竟MVVM只是一種設(shè)計模式,是代碼設(shè)計經(jīng)驗,需要按需判斷。但我們在考慮是否采用或者轉(zhuǎn)換成MVVM時需要清楚以下幾點:

? ? ? ? (1)MVVM可以兼容MVC

? ? ? ? (2)MVVM為單元測試提供對象(ViewModel)

? ? ? ? (3)MVVM適合配合綁定機(jī)制使用

3.單例模式

????????單例模式大概是設(shè)計模式中最簡單的一個,它的定義是:保證一個類只有一個實例,并且提供一個全局的訪問入口訪問這個實例(Ensures?aclasshas?only?one?instance,?and?provide?a?global?point?of?access?to?it.)。它作用是可以保證在程序運行過程,一個類只有一個實例,而且該實例易于供外界訪問從而方便地控制了實例個數(shù),并節(jié)約系統(tǒng)資源。


單例模式的結(jié)構(gòu)靜態(tài)圖

? ? ? ? 單例模式在實際的應(yīng)用場景中提供了一個為人熟知的訪問點,為客戶類共享資源生成唯一實例,并通過該實例共享資源?;蛟S我們平時使用中習(xí)慣使用全局對象或者類方法來提供一個類似的訪問點,但是全局對象無法防止類被實例化一次以上,而且類方法也缺少消除耦合的靈活性。舉一個例子,我給整個應(yīng)用程序定義了一個全局的變量,用于我在編寫這個項目工程中共享和訪問這個資源,然而因為在App應(yīng)用場景越來越復(fù)雜的情況下,我和同事之間負(fù)責(zé)的功能或模塊必然會有交集,有可能他也在某處定義了一個相同的全局變量,若在后期Code Review中再回頭來協(xié)同處理這些全局變量在開發(fā)成本和效率上會帶來的不小的影響。而類方法得作用是提供方法用于共享服務(wù),沒有創(chuàng)建可以共享的資源的實例。

4.觀察者模式

????????觀察者模式亦稱為發(fā)布-訂閱模式,它的基本概念是:定義對象見的一種一對多的依賴關(guān)系,當(dāng)一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并自動更新。它就像是訂閱雜志一樣,讀者把名字和郵寄地址提供給出版社進(jìn)行雜志訂閱。出版社保證按照讀者的郵寄地址準(zhǔn)確無誤地將雜志送至讀者手中,沒有訂閱就不會收到該雜志。觀察者模式就是如訂閱雜志這樣,觀察者在出版社-通知器中注冊自己到特定的通知產(chǎn)生類似訂閱雜志的行為,當(dāng)有通知發(fā)出的時候,觀察者通過通知器便能獲取到該通知。


觀察者模式的結(jié)構(gòu)靜態(tài)圖

????????觀察者模式的思路如結(jié)構(gòu)靜態(tài)圖所示,Subject提供注冊和取消注冊的方法,任何實現(xiàn)Observer協(xié)議而且想要處理update消息的對象,都可以注冊或取消。當(dāng)Subject的實力發(fā)生變更時,它會向自己發(fā)送notify消息,向已注冊的觀察者廣播update消息。

? ? ? ? 使用觀察者模式的優(yōu)勢是,可以用多個Observer來擴(kuò)展Subject的行為,這些Observer具有處理存儲在Subject中的信息的特定實現(xiàn)。它也可以說是消除不同對象之間的耦合的一種設(shè)計模式。當(dāng)我們在遇上以下情形的時候,可以優(yōu)先考慮使用觀察者模式:

? ? ? ? (1)因為一個對象的改變需要同時改變其他對象

? ? ? ? (2)一個對象需要對其他的對象進(jìn)行通知

5.代理模式

? ? ? ? 在平時生活中,提供免費試用品或試用期是相當(dāng)常見的促銷手段,對于一些價格較貴的商品或者在線訂閱服務(wù),這樣的促銷手段尤為有效。那么引申出來,試用品和試用期就可以當(dāng)作做代理,代理的一個常見用處是作為一個輕量的替身對象,它允許客戶端首先訪問某些便宜的信息或功能,直到真真需要使用更有價值更高級的功能時,代理就會為客戶端準(zhǔn)備真正的“商品”。代理在通常來講是一種替代或者占位,它控制對另一些對象的訪問,而這些對象可能是遠(yuǎn)程對象,開銷較大的對象或者是對安全性有要求的對象。而這一思想細(xì)化而來的一種模式即為代理模式。

? ? ? ? 代理模式是為其他對象提供一種代理以控制對這個對象的訪問。它的思想是使用一個基本上跟實體對象行為相同的代理,客戶端無需知曉面對的代理是否是一個實體對象,當(dāng)客戶端請求某些創(chuàng)建的開銷較大的功能是,代理將把請求轉(zhuǎn)發(fā)給實體對象,準(zhǔn)備好請求的功能并返回給客戶端。


代理模式類圖

? ? ? ? 如類圖所示,當(dāng)客戶端Client向Proxy對象發(fā)送request消息時,Proxy對象會把這個消息轉(zhuǎn)發(fā)給Proxy對象之中的RealSubject對象。而RealSubject才是實際實施操作間接滿足客戶端請求的對象。

? ? ? ? iOS對于代理模式的支持很好,因為Objective-C是不支持多繼承的,很多時候我們都使用Protocol協(xié)議。Protocol協(xié)議定義了一套公用的接口,但不能提供具體的實現(xiàn)方法,因為具體的實現(xiàn)方法需要由協(xié)議的代理對象去完成。協(xié)議可以繼承其他協(xié)議,并且可以繼承多個協(xié)議。

????????首先我們需要了解到協(xié)議存在兩個修飾符optional和required,在沒有特別聲明的情況下,協(xié)議默認(rèn)為required,協(xié)議的代理對象是delegate。下面我們將用一個簡單的Demo來描述Protocol協(xié)議:

? ? ? ? 1.創(chuàng)建協(xié)議類?ProtocolDelegate.h


? ? ? ? 2.創(chuàng)建協(xié)議代理對象ProtocolDelegateViewController


ProtocolDelegateViewController.h? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?


ProtocolDelegateViewController.m? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? 3.創(chuàng)建協(xié)議委托對象ProtocolViewController


ProtocolViewController.m


委托代理傳值

6.工廠模式

????????工廠方法是我們在應(yīng)用程序開發(fā)中最常見的模式,我們通過具體工廠重載其抽象工廠父類定義的工廠方法來創(chuàng)建自己的對象。工廠方法也成為虛擬構(gòu)造器。它適用于一個類無法與其生成拿個類對象,想讓其子類來制定所生成的對象。因此,工廠模式可以定義為:定義創(chuàng)建對象的接口,讓子類決定實例化哪一個類。工廠方法使得一個類的實例化延遲到其子類。


工廠模式類圖

? ? ? ? 如類圖所示,抽象的產(chǎn)品(Product)定義了工廠方法創(chuàng)建的對象借口。具體對象(ConcreteProduct)實現(xiàn)了產(chǎn)品接口。Creator定義了返回產(chǎn)品對象的工廠方法。它也可以為工廠方法定義一個實現(xiàn),返回默認(rèn)具體對象。Creator的其他操作也可以調(diào)用此工廠方法創(chuàng)建產(chǎn)品對象。ConcreteCreator是Creator的子類,它通過重載工廠方法以返回具體產(chǎn)品的實例。

? ? ? ? 一般來說,當(dāng)我們在編譯時無法準(zhǔn)確預(yù)期要的創(chuàng)建的對象的類,類想讓其子類決定在運行時創(chuàng)建的產(chǎn)品,或者當(dāng)類存在若干個輔助子類而我們想將返回的具體子類信息局部化時將會使用到工廠模式。工廠模式能給予類在變更返回哪一種對象這一點上更多的靈活性。

????????工廠模式讓應(yīng)用程序可以要求由工廠方法創(chuàng)建的對象擁有一組共同的行為。當(dāng)我們在類層中加入新的具體產(chǎn)品時,并不用修改原代碼,因為我們定義創(chuàng)建對象的接口一直不變。

? ? ? ? 下面我將從一個成衣工廠的Demo來代碼實現(xiàn)工廠模式:

? ? ? ? 1.首先我們定義成衣產(chǎn)品的基類Clothe

Clothe.h

? ? ? ? 2.然后派生出兩個子類,襯衣類和T恤類

Tshirt.m
Shirt.m

3.定義工廠基類ClotheFactory


ClotheFactory.h

4.派生出兩個工廠子類ShirtFactory和TshirtFactory


TshirtFactory.m
ShirtFactory.m

? ? ? ? 這兩個工廠子類的中,我重載了工廠方法,返回子工廠生產(chǎn)的具體產(chǎn)品對象。

5.子類工廠調(diào)用


方法調(diào)用

最終我們在演示用的視圖控制器中設(shè)定兩個按鈕,通過分別觸發(fā)兩個按鈕來調(diào)用子類工廠返回產(chǎn)品對象的方法,并通過界面輸出產(chǎn)品名稱來查看具體的實際產(chǎn)品。


襯衣子類方法調(diào)用
T恤子類方法調(diào)用

? ? ? ? 以上就是這次對iOS設(shè)計模式的總結(jié),第一次寫簡書文中還有很多不足的地方,后面會加強文章的撰寫能力。

這個是本文章DEMO的地址:Github

參考資料

《Objective-C編程之道》

淺談iOS中MVVM的架構(gòu)設(shè)計與團(tuán)隊協(xié)作

我對iOS開發(fā)中使用MVVM的理解和使用

iOS 中的 21 種設(shè)計模式

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 小白程序員只能看懂源代碼,而大神程序員能看懂文檔。 設(shè)計模式:為解決特定場景的問題而定制的解決方案。設(shè)計原則:構(gòu)建...
    印林泉閱讀 976評論 0 8
  • 傳統(tǒng)模式下的開發(fā)MVCMVVM基于面向協(xié)議MVP的介紹MVP實戰(zhàn)開發(fā)說在前面:相信就算你是個iOS新手也應(yīng)該聽說過...
    行走的菜譜閱讀 3,317評論 1 5
  • 圖片發(fā)自簡書App 有人說,我的身體是我自己的,但,真的是這樣嗎,如果你連他是怎么運動的都不知,又怎么能說是你自己...
    三生三石緣閱讀 644評論 0 1
  • 千里迢迢,確實不易。 但距離產(chǎn)生美也不是沒有道理。 太多的等待與期盼,這是一開始就明白的過程,雖然逃不了思念的辛苦...
    暖暖愛閱讀 235評論 0 0
  • 充滿好奇,一切對我來說都是未知數(shù),就這樣我出去了。從香港機(jī)場起飛,到吉隆坡轉(zhuǎn)機(jī),再飛到了古晉這個陌生的城市里。 ...

友情鏈接更多精彩內(nèi)容