隨着公司業務的不斷髮展,項目的功能愈來愈複雜而傳統的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 以外,網上還有 JLRoutes,Routable-iOS,ABRouter 等等開源的方案說明大部分人仍是承認這種解耦方式的。再加上 ModuleManager
這種面向接口的模塊管理工具(代碼實現能夠參考念紀的 AppLord),若是用的好的話,已經可以把整個代碼的依賴拆分的比較清楚了。
這套方案差很少是我目前爲止看到的最優秀的解耦方案了,從中能夠看到做者不少的積澱和思考。
有步驟講解視頻以及優化後的項目源碼資料.由於簡書文章沒有地方放.你們能夠加一下個人羣獲取一下。在羣裏討論一下組件化技術這一塊。 QQ羣號:656315826.