1. 程式人生 > >iOS 最佳實踐:重構AppDelegate

iOS 最佳實踐:重構AppDelegate

引言

可能很多讀者可能都有這樣的經歷,迭代維護多年的系統程式碼量激增,有些模組的程式碼自己都覺得醜陋,可是卻不敢重構,生怕一不小心被拉取祭天,然後來了個愣頭青實習生正好參與這個模組迭代,一頓騷操作後這個模組炸了,那麼面對屎山一樣焦灼耦合的程式碼,面對產品汪隨著手機殼顏色變化APP主題這種變態需求的時候,如何不在這坨屎山裡修修補補,如何重構屎山,讓你的程式碼成為金字塔一樣的藝術品?

老峰最近讀了V8tr寫的Refactoring Massive App Delegate感覺寫的挺好,就翻譯過來分享給大家,正好以AppDelegate重構來討論下如何重構複雜業務程式碼。

AppDelegate連線應用程式和系統,通常被認為是每個iOS專案的核心。隨著開發的迭代升級,不斷增加新的功能和職責,它的程式碼量也不斷增長,最終導致了Massive AppDelegate(臃腫的AppDelegate)。

在複雜App Delegate裡修改任何東西的成本都是很高的,因為它將會影響你的整個APP,一不留神就吃bug。毫無疑問,保持AppDelegate的簡潔和清晰對於健康的iOS架構來說是至關重要的。本文我們將使用多種方法來重構,使之簡潔、可重用和可測試。

Massive AppDelegate 的問題

AppDelegate是應用程式的根物件。它確保應用程式與系統以及其他應用程式正確的互動。AppDelegate理通常會承擔很多職責,這使得很難進行更改,擴充套件和測試。

通過調研幾十個最受歡迎的開源iOS應用程式,我把AppDelegate常見的業務程式碼列出如下。我相信我的讀者也寫過這樣的程式碼,或者維護或者支援這種類似混亂的專案。

  1. 初始化許多第三方庫(如分享,日誌,第三方登陸,支付)
  2. 初始化資料儲存系統
  3. 管理UserDefaults:設定首先啟動標誌,儲存和載入資料
  4. 管理通知:請求許可權,儲存令牌,處理自定義操作,將通知傳播到應用程式的其餘部分
  5. 配置UIAppearance
  6. 管理App Badge Counter
  7. 管理後臺任務
  8. 管理UI堆疊配置:選擇初始檢視控制器,執行根檢視控制器轉換
  9. 日誌埋點統計資料分析
  10. 管理裝置方向
  11. 更新位置資訊

這些臃腫的程式碼是反模式的,像屎一樣難於維護。顯然支援擴充套件和測試這樣的類非常複雜且容易出錯。例如,檢視Telegram的AppDelegate的原始碼會激起我的恐懼。Massive App Delegates與我們經常談的Massive View Controller的症狀非常類似。

在我們同意Massive App Delegate的問題存在並且非常重要之後,讓我們看看可能的解決方案,每個Recipe(方案)遵循單一職責、易於擴充套件、易於測試原則。下面列出Recipes。

Recipe #1:(Command Design Pattern)命令模式

命令模式(Command Pattern)是一種資料驅動的設計模式,它屬於行為型模式。請求以命令的形式包裹在物件中,並傳給呼叫物件。呼叫物件尋找可以處理該命令的合適的物件,並把該命令傳給相應的物件,該物件執行命令。因此命令的呼叫者無需關心命令做了什麼以及響應者是誰。

可以為APPdelegate的每一個職責定義一個命令,這個命令的名字有他們自己指定 在這裡插入圖片描述

然後我們定義StartupCommandsBuilder來封裝如何建立命令的詳細資訊。APPdelegate呼叫這個builder去初始化命令並執行這些命令 在這裡插入圖片描述

最後只需在didFinishLaunchingWithOptions中初始化就可以了 在這裡插入圖片描述

如果APPdelegate需要新增新的職責,則可以建立新的命令,然後把命令新增到Builder裡去而無需去改變AppDelegate。解決方案滿足單一職責、易於擴充套件、易於測試原則。

Recipe #2: Composite Design Pattern 組合設計模式 組合模式

組合模式(Composite Pattern),又叫部分整體模式,是用於把一組相似的物件當作一個單一的物件。組合模式依據樹形結構來組合物件,用來表示部分以及整體層次。這種型別的設計模式屬於結構型模式,它建立了物件組的樹形結構。一個很明顯的例子就是iOS裡的UIView以及它的subviews。

這個想法主要是有一個組裝類和葉子類,每個葉子類負責一個職責,而組裝類負責呼叫所有葉子類的方法。 在這裡插入圖片描述

接下來,實現執行具體職責的葉子類 在這裡插入圖片描述

我們定義AppDelegateFactory來封裝建立的邏輯,在AppDelegate通過工廠方法建立組裝類,然後通過他去呼叫所有的方法 在這裡插入圖片描述

他滿足我們在開始時提出的所有要求,如果要新增一個新的功能,很容易新增一個葉子類,無需改變AppDelegate,解決方案滿足單一職責、易於擴充套件、易於測試原則。

Recipe #3: Mediator Design Pattern 中介者模式

中介者模式(Mediator Pattern)是用來降低多個物件和類之間的通訊複雜性。這種模式提供了一箇中介類,該類通常處理不同類之間的通訊,並支援鬆耦合,使程式碼易於維護。中介者模式屬於行為型模式。

如果您想了解有關此模式的更多資訊,我建議您檢視Mediator Pattern Case Study。或者閱讀文末老峰也給出關於設計模式比較經典的書籍。

讓我們定義AppLifecycleMediator將UIApplication的生命週期通知底下的監聽者,這些監聽者必須遵循AppLifecycleListener協議,如果需要監聽者要能擴充套件新的方法。 在這裡插入圖片描述

定義AppLifecycleListener協議,以及協議的的實現者 在這裡插入圖片描述

我們定義好靜太例項方法,初始化所有監聽者 在這裡插入圖片描述

現在它只需要1行程式碼就能加入到AppDelegate中 在這裡插入圖片描述

這個中介者自動訂閱了所有的事件。AppDelegate僅僅需要初始化它一次,就能讓他正常工作。每個監聽者都有一個單一職責,很容易新增一個監聽者,而無需改變Appdelgate的內容,每個監聽者以及中介者能夠容易的被單獨測試。

總結

我們認為大多數AppDelegates的設計都不太合理,過於複雜並且職責過多。我們稱這樣的類為Massive App Delegates。

通過應用軟體設計模式,Massive App Delegate可以分成幾個單獨的類,每個類都有單一的責任,可以單獨測試。

其實本文中的解耦方法並不侷限於在App Delegate中使用,我們的UIViewController也可以採用設計模式去優化去解耦,本文原始碼見文末。

這樣的程式碼很容易更改維護,因為它不會在您的應用程式中產生一連串的更改。它非常靈活,可以在將來提取和重用。

推薦閱讀: