淺談設計模式在iOS開發實戰專案中的應用

Edgars發表於2019-03-01

       在我們日常的開發中設計模式伴隨著專案的各個模組,巧妙地使用設計模式可以讓我們寫出更高效,簡潔,優美的程式碼。可是因為對於設計模式的不熟悉,很多高效的設計模式並沒有被很好地使用起來,而最近也正好在review同事和自己曾經寫的一些程式碼,然後在優化的過程中談一下我們在專案中使用設計模式做出的一些優化。當然只是個人看法,有任何的不足歡迎拍磚,大家一起探討和成長。

1.在專案中使用delegate pattern(代理模式)和block的抉擇

       之前在技術交流群中看到技術大神在爭論block和delegate使用哪一種該如何抉擇的問題,看到有人說delegate傳遞的是指標而block傳遞的是一個結構體,在這個角度出發確實是delegate更好一些,但是在我們實際的開發環境中,我更願意結合具體的業務場景做出不一樣的選擇,因為delegate在程式碼的可讀性上是不如block好的,具體而言我們主要做了如下的抉擇。

      首先在網路請求層的處理上對delegate和block都做了封裝,原因就是在具體的業務中會出現在A類中傳送了請求,可是我們返回的資料建立的對應模型要在B類中才會去呼叫,這個時候我們使用block來傳遞資料模型,因為這時使用代理可能要封裝兩層甚至多層的代理這裡無疑就將程式碼的可讀性變得很差。如果模型傳遞的更多層,程式碼會顯得異常混亂。

       第二在實際開發中有些複雜介面會用到dispatch_group_t的情況,這個時候如果是要對網路請求做合併處理的,如果這個時候在同一個方法中我們傳送了兩個甚至更多的網路請求,此時如果要是使用delegate來回撥返回結果,一般會將dispatch_group_t宣告成一個屬性,在代理中使用dispatch_group_leave(self.group)這樣的方式來獲取回撥結果,然後在dispatch_group_notify中做統一的處理,我認為這樣對於group的記憶體管理就變得不在合理,所以這個時候我是用的block。 剩下的在一個介面中的時候,我更多的會用#prama mark 的方法區分出一個請求,用代理的方式會寫請求。

      當然除了網路請求層的處理之外,我們是不是在其他地方也對delegate和block有過抉擇呢,這一點上一定會有的。我記得前不久我們在做 <U運動>健身教練直播版本開發的過程中就遇到過,我相信大家對於直播介面是不陌生的,如果點選主播頭像,觀眾頭像,評論區的暱稱都會顯示使用者的資料彈窗的。可是這三個部分被拆分到了三個小的試圖類中,當時同事提出每個點選事件用block的方式進行回撥,寫一個manager管理類,對彈出使用者資料進行統一的處理,我想很多人第一時間都會想到這樣的處理方案,但是後來卻用了代理的方案。

淺談設計模式在iOS開發實戰專案中的應用

       方案的程式碼結構如上圖,就是一個簡單的demo,也就是說我們將代理模式進行了區分,所有獲取使用者資料的點選事件都走baseMethod1的代理 一樣可以做到所有使用者的獲取資料的點選事件走到controller的一個方法中,也不再需要去為此建立一個manager,甚至也不需要在每個試圖中區公開一個回撥的方法,感覺在程式碼的簡潔和清晰上都有了提高,此外也可以相容每個試圖有自己的回撥事件。所以在delegate模式和block的抉擇中並不是一定的,要結合具體的業務的場景做出自己的分析然後做出選擇。

2.關於adapter pattern(介面卡模式)的使用

我想一些同學在陪伴專案成長的過程中很多都遇到過這樣的一個問題,就是將伺服器返回的資料轉換成一個資料模型然後傳入各個試圖的介面渲染介面,但是有的時候產品告訴我們,我的使用者資料想多要一個引數來呈現,如果介面名命名成多個引數名的形式,那麼勢必會很麻煩改動很多曾經呼叫的地方。這個時候有的小夥伴會說介面傳入引數是一個類就好了,但是如果使用者資料要在多個介面進行呈現的方式是一樣的,但是每個介面整體返回的資料又是不一樣的情況下,如果介面用類來做引數,可能就需要在拆分出來的使用者資料的試圖中提供很多的介面,然後暴露給介面呼叫,顯然這樣的方式也是不合理的。所以這個時候怎麼樣解決呢,於是出現了介面卡模式。程式碼結構如下

淺談設計模式在iOS開發實戰專案中的應用
介面卡模式使用

       如果在介面卡模式下,我們再給多處需要用到的試圖傳入引數的時候就不用介面定義多個引數或者是類了,這個時候我們定義的引數是遵守某個協議的資料模型,我們在每個介面返回的資料模型中遵守對應的協議就可以了。如果產品再來告訴我們改需求,我們就在協議中對應的新增方法,然後搜尋下遵守對應協議的類實現這個方法就好了,介面的處理就會變得簡單。當然對於介面卡的使用我只是簡單的分析。它絕不只是用在適配介面,我們在真實的專案中進入有些controller也是用的這樣的方案,甚至介面卡協議還要再去做遵守協議的操作,在它的上層在建立一個介面卡,這個就需要結合具體的業務場景了。但是介面卡在增加程式碼的可讀性以及簡化程式碼上真的可以給我們很大的幫助,更好的使用還是需要小夥伴們不斷地嘗試和想象的~~~

3.關於singleton pattern(單例模式)的使用

       我想對於絕大多數開發者而言,這種開發模式對於我們而言都是再熟悉不過的。這裡要說單例模式的原因是我認為單例在很多的專案中可能有些被過分的使用了,一個專案中可能會出現幾十個甚至更多的單例。

       我們都知道,在一個單例被建立之後會伴隨客戶端的整個生命週期,在程式結束之前單例是不會被釋放的,所以從記憶體管理的角度上單例的使用是應該被注意的。應該知道什麼場景下我們適合使用單例,在什麼樣的業務場景下我們可以避免使用單例以節省我們的記憶體空間。比如說加入我們做了一個直播,有些同學可能為了記錄使用者是不是在直播中去建立一個單例來判斷使用者當前的狀態,然後限制使用者的一些行為。其實這樣的場景下,我認為使用單例就是一種不合理的行為,因為在這種模式下,我們完全可以在直播管理類中建立一個類方法建立一個方法,將當前狀態儲存在NSUserDefault中進行狀態的判斷,這樣節省了對應的記憶體,也避免了不合理的浪費記憶體空間,淡然和這裡相似的距離有很多。希望處理不當的同學可以檢查一下自己的專案,做一個更優的處理方案。

4.一些其他的設計模式中可能需要注意的問題

       除了上邊的最常用的設計模式之外,我們在專案中常用的設計模式還有工廠模式,觀察者,策略等模式和部分專案中用到的中介者,模板,享元等模式。

       首先想說的就是觀察者模式,在iOS實際開發中,我想大家都用到過NSNotificationCenter和KVO或者FBKVO.但是我想不是所有同學都知道NSNotificationCenter 的observer 收到訊息的方法中所在的確切執行緒的。其實收到訊息後執行的方法所在的執行緒是和post訊息時所線上程是一致的,所以這是可能就會出現執行緒安全的問題,雖然蘋果在官方的文件中說做過處理,但是在實際開發中並不意味著不會出現問題。具體可以參考這篇文章,裡邊介紹了出現問題的場景,在我們的專案中使用KVO時遇到過這樣的情況的。

      至於策略模式,我想大家日常的開發中都有用到過,只是我們有些同學不知道這個叫策略而已~~~其實策略的使用使用真的可以大幅度的提升程式的可讀性的,所以不知道的小夥伴一定要百度一下,我在這裡就不詳細介紹啦。

      而中介者模式個人感覺主要用在元件化開發中做URL的跳轉使用,我們的專案一直希望想向元件化開發的方向做努力,所以最近可能會深入的研究這一部分,如果有了成果在和童鞋們分享,要說的太多,這裡就不做擴充套件了。

      模板模式在專案中的使用其實是可以和介面卡模式相結合一起來玩的,所以研究過介面卡的小夥伴,對於這裡一定再熟悉不過,如果對於這塊不是很瞭解,真的建議很好地去進行學習和關注,良好的程式碼質量很重要。

      最後說道享元模式,我說很少的專案中用到其實是個很嚴重的錯誤,因為每個專案我相信一定都會有tableview而它的cell複用池機制就是基於享元模式設計的,嚴格上說享元模式在企業專案中被自己設計和使用還是比較少的。但是當我們需要複用大量資料的時候考慮到效能等方面的問題,不防考慮下這個模式,然後做相應的優化,一定會有意想不到奇效~~~

      文章的最後,想說其實我這個人很懶,不喜歡寫文章,自己寫的一些小實驗也都傻傻的停留在了自己的電腦上,但是最近身邊發生的一些事讓我的態度有了改變,所以從今以後,我應該會強制的要求自己每週至少寫一篇滿滿都是自己淺顯看法的文章,將自己的小想法和無聊生產的小輪子都放到git上去,有任何意見和不滿歡迎在這裡吐槽,拍磚。當然更希望可以和熱愛iOS開發的童鞋們一起成長~~~

相關文章