iOS組件化——蘑菇街案例分析

序言

隨着公司業務的不斷髮展,項目的功能愈來愈複雜而傳統的MVC或者MVVM架構已經沒法高效的管理工程代碼,所以須要用一種技術來更好地管理工程,因而研究了一下新項目的架構選型,通過一番選擇,決定使用組件化的架構.ios

若是和我討論或者想拿源碼和資料的, 請聯繫我時,備註一下組件化 加我技術交流QQ羣:656315826git

什麼是組件化

組件化開發,就是將一個臃腫,複雜的單一工程的項目, 根據功能或者屬性進行分解,拆分紅爲各個獨立的功能模塊或者組件 ; 而後根據項目和業務的需求,按照某種方式, 任意組織成一個擁有完整業務邏輯的工程。這就是所謂的組件化開發。github

優勢

一、組件之間相互獨立。各組件開發成員之間的代碼想相互獨立編寫的,獨立編譯,獨立運行和獨立測試的。 二、資源的重複裏用,尤爲是功能性,工具性的代碼,能夠很輕鬆的重複裏用 三、迭代的效率提升。經過迭代進行功能的增減,只須要進行組件的拆分和組合。很方便也很高效網絡

缺點

一、增長了代碼的冗餘,組件化顆粒度越細,中間代碼越多 二、增長了項目的複雜度,複雜度越高越容易出問題 三、學習成本高,對於開發人員對各類工具的掌握要求也比較高,對於新手來講入門較爲困難。 四、因爲工具和流程的複雜化,致使團隊之間協做的成本變高,某些狀況下可能會致使開發效率降低。架構

但長遠來看,組件化帶來的好處是遠遠大於壞處的,特別是隨着項目的規模增大,這種好處會變得愈來愈明顯。工具

怎麼作組件化

以蘑菇街爲例,使用 CocoaPods 來作這件事的話,咱們能夠拆到主工程能夠一行代碼都沒有,只有一個 Podfile,相似於下面這樣:組件化

pod 'MGJiPhone-Foundation'
pod 'MGJiPhone-Hybrid'

pod 'MGJiPhone-Detail'
pod 'MGJiPhone-Me'
pod 'MGJiPhone-Shop'
# ...

在最理想的狀況下,這些子工程直接應該只存在上層到下層的依賴,即業務模塊對底層基礎模塊的依賴,業務工程之間儘量不出現橫向依賴。從 limboy 的描述來看,蘑菇街各個子模塊是能夠單獨編譯出東西來的,這說明各個子模塊之間的橫向依賴已經不多,證實子模塊之間的拆分已經比較成功了。學習

理想很豐滿,現實很骨感。在咱們對一個工程開刀的過程當中,會發現事情遠沒有那麼簡單。繼續以蘑菇街 App 爲例,例如咱們想拆分 Detail 模塊(即商品詳情模塊),Detail 模塊中可能包含了下面諸多依賴:測試

#import "MGJShopViewController.h"
#import "MGJShopRequest.h"
#import "MGJUser.h"
#import "MGJCart.h"
#import "MGJFoundation.h"
#import "MGJWebViewController.h"
#import "MGJHybridAPI.h"

爲何會出現這麼多依賴?由於 Detail 模塊自己的業務就須要涉及到和多個不一樣模塊之間進行交換,例如從用戶模塊得到用戶的信息,當用戶購物時和購物車模塊進行交互,展現商品內容時和 Web 和 Hybrid 模塊進行交互等等。這是業務自己決定的,咱們沒辦法改變。咱們所能作的是儘量地減小橫向的依賴。優化

上面也提到了橫向依賴這個概念。這裏說明一下,業務模塊沒有依賴是不可能的,咱們但願作到的是,它只依賴那些底層的基礎模塊,而不依賴於和它同級的業務模塊。

基礎依賴

哪些模塊算是底層的基礎依賴?一個最簡單的判斷辦法就是,看這個部分的代碼是否是穩定的。最多見的基礎依賴,包括穩定的三方庫,底層網絡通訊模塊,經常使用的 category 等等。這些代碼不會頻繁改動,能夠做爲基礎依賴。

基礎依賴在保持穩定的基礎之上,還須要作到高複用性和單一職責性。這就要涉及到你們常常會去作的一件事了——建立 Common 模塊。Common 模塊可能會存一些經常使用的 category,helper,utils 等等東西:

pod 'MGJiPhone-Common'

最開始的時候這麼作會顯的很方便,可是隨着項目規模的增加,整個 Common 模塊最終會成爲依賴管理的噩夢。Common 自己做爲一個模塊集各類依賴於一身,缺少內部的橫向解耦,致使其總體的複用性很是差,簡直是剪不斷理還亂。所以最好一開始就避免建立 Common 模塊,讓每一個模塊都保持儘可能少的職責:

pod 'MGJiPhone-Location'
pod 'MJGiPhone-Device'
pod 'MGJiPhone-NSStringCategory'
pod 'MGJiPhone-NSDateCategory'

橫向依賴

把基礎模塊拆分完以後,下面須要對業務模塊之間橫向的依賴進行拆解。這部分是比較難也是容易碰到問題的。對於兩個模塊之間的 vc 常見的 push 操做:

LanguageViewController *vc = [[LanguageViewController alloc] init];
vc.selectedIndex = self.currentSelectedIndex;
[self.navigationController pushViewController:vc animated:YES];

能夠經過引入 Router 來去除對於 vc 類的強依賴:

// 註冊
[[HHRouter shared] map:@"/lang/:index/" toControllerClass:[LanguageViewController class]];

// 獲取
UIViewController *vc = [[HHRouter shared] matchController:@"/lang/1/"];
[self.navigationController pushViewController:vc animated:YES];

這種辦法不只能夠用於 Controller,用於普通的對象也是能夠的。Router 能夠自動取得對應的類,並進行實例化。對於不須要實例化的模塊來講,蘑菇街的解決辦法中引入了 ObjectHandler

[MGJRouter registerURLPattern:@"mgj://cart/ordercount" toObjectHandler:^id(NSDictionary *routerParamters){
    // do some calculation
    return @42;
}]

以及面向接口思想的 ModuleManager,作到了依賴於接口(protocol)而不依賴於實現。

以我淺薄的開發經驗看來,基於 Router 的這種解決方案已經能處理大部分狀況了,除了 HHRouter 以外,網上還有 JLRoutesRoutable-iOSABRouter 等等開源的方案說明大部分人仍是承認這種解耦方式的。再加上 ModuleManager 這種面向接口的模塊管理工具(代碼實現能夠參考念紀的 AppLord),若是用的好的話,已經可以把整個代碼的依賴拆分的比較清楚了。

這套方案差很少是我目前爲止看到的最優秀的解耦方案了,從中能夠看到做者不少的積澱和思考。

代碼獲取

有步驟講解視頻以及優化後的項目源碼資料.由於簡書文章沒有地方放.你們能夠加一下個人羣獲取一下。在羣裏討論一下組件化技術這一塊。 QQ羣號:656315826.

相關文章
相關標籤/搜索