iOS開發-APP組件模塊化的理解

模塊化的意義

當項目大到一定程度,開發人員也多,所有的代碼都集中到一個倉庫,提交修改都要等其他人提交完成不報錯才能開始,非常麻煩。

再者就是代碼之間耦合嚴重,到處引用,穿插錯綜複雜,往往改變一個變量,需要修改很多處代碼,很容易出錯。

對於這種情況,就要進行架構整治,模塊化無疑是一個好的方案。


模塊化的粒度

對於模塊化,並不是一味的全部分離成模塊就是最好的。模塊之間或許會有必要的引用以及上下級依賴關係,沒必要完全的獨立。再者需要考慮到業務變化時,可能又要重新劃分模塊,工作量和成本又高了。

iOS 模塊化的劃分應該遵循 SOLID原則 ,如下幾點:

  • (S)單一原則:對象的功能要單一,不要是很多功能的集合體

例如CALayer負責動畫視圖顯示,UIView則負責事件傳遞,事件響應

  • (O)開閉原則:“開”,是指對於組件功能的擴展是開放的,是允許對其進行功能擴展的;開閉原則中“閉”,是指對於原有代碼的修改是封閉的,即不應該修改原有的代碼。
  • (L)里氏替換原則:子類對象是可以替換基類對象的。所有引用基類的地方必須能透明地使用其子類的對象。

例如KVO的實現機制,利用isa-swizzling父類指向子類。

  • (I)接口隔離原則:接口的用途要單一,不要一個接口上根據入參不同實現不同的功能。

可以使用多個專門的協議,而不是使用一個龐大臃腫的協議。

  • (D)依賴反轉原則:方法應該依賴抽象,不要依賴實例。面向接口編程,不要面向實現編程。讓調用接口感覺不到內部是如何操作。

還一個 (D)迪米特法則:如果兩個軟件實體無須直接通信,那麼就不應當發生直接的相互調用,可以通過第三方轉發該調用。其目的是降低類之間的耦合度,提高模塊的相對獨立性。即高聚合,低耦合。
可以順帶記憶


組件

可組裝,獨立的業務單元,高內聚,低耦合的特性。

iOS開發的組件,不應是UI控件,也不是UIViewController這種大UI和功能的集合,應該是包含UI控件,小功能集合的組件這樣劃分。


組件化方案

MGJRouter 的路由映射

https://github.com/meili/MGJRouter

蘑菇街的組件化方案 MGJRouter

[MGJRouter registerURLPattern:@"mgj://detail?id=:id" toHandler:^(NSDictionary *routerParameters) {
    NSNumber *id = routerParameters[@"id"];
    // create view controller with id
    // push view controller
}];

是一個路由方案url-block,通過註冊urlblock到一個單例中的字典routes中。
當調用

[MGJRouter openURL:@"mgj://detail?id=404"]

就通過Url去從字典routes取其block來執行。這樣內存中維護了很多映射關係,Url這樣的使用方式,也比較繁瑣。而且需要將Url的時機必須要在調用之前,在+load進行註冊又拖長了App啓動時間,在其他時機註冊又需要統籌兼顧。

另外還有protocol-classurl-controller,這些方式都大同小異,需要維護一個映射表,是一個短板,個人更傾向於CTMediator這種中間者架構


CTMediator 中間者

https://github.com/casatwy/CTMediator

其實就是使用runtime通過[target performSelector:action withObject:params];取到需要的數據,例如界面,視圖。

如何使用這些界面視圖就不關CTMediator的事了,這些界面,視圖就可以封裝成單獨的模塊,互無關係。


Category的編寫

CTMediator的關鍵在於其分類的編寫,每個模塊功能的分類由其模塊開發者編寫。

- (UIViewController *)CTMediator_viewControllerForDetail
{
    UIViewController *viewController = [self performTarget:kCTMediatorTargetA
                                                    action:kCTMediatorActionNativeFetchDetailViewController
                                                    params:@{@"key":@"value"}
                                         shouldCacheTarget:NO
                                        ];
    if ([viewController isKindOfClass:[UIViewController class]]) {
        // view controller 交付出去之後,可以由外界選擇是push還是present
        return viewController;
    } else {
        // 這裏處理異常場景,具體如何處理取決於產品
        return [[UIViewController alloc] init];
    }
}

這是demo中分類的一個方法實現,kCTMediatorTargetA隸屬於模塊A

kCTMediatorTargetA中有一個kCTMediatorActionNativeFetchDetailViewController方法可以獲取一個UIViewController`,

通過寫CTMediator對於模塊A的分類,就可以獲取模塊A中相關的界面以及UI,例如CTMediator_viewControllerForDetail

在這裏插入圖片描述
這樣的優勢在於,沒有了key-value的映射關係,不需要維護url映射表,更不需要存儲block塊,Category For A由開發模塊A的人員來寫,他很熟悉模塊A(對於他來說將模塊A中某個界面取出,並設置相關參數是很簡單的事情),通過分類再轉給不熟悉的人(無需關心模塊A的內容)使用,就很方便了。

對於遠程url調用,同樣是通過將url解析成對應的動作,例如取某個視圖,推出某個界面。


組件化能讓工程架構更加清晰,每個人負責一個模塊,通過pod導入,互不影響。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章