整體架構
casatwy組件化方案分爲兩種調用方式,遠程調用和本地調用,對於兩個不同的調用方式分別對應兩個接口。
遠程調用通過
AppDelegate
代理方法傳遞到當前應用後,調用遠程接口並在內部做一些處理,處理完成後會在遠程接口內部調用本地接口,以實現本地調用爲遠程調用服務。本地調用由
performTarget:action:params:
方法負責,但調用方一般不直接調用performTarget:
方法。CTMediator
會對外提供明確參數和方法名的方法,在方法內部調用performTarget:
方法和參數的轉換。
casatwy提出的組件化架構
架構設計思路
casatwy是通過CTMediator
類實現組件化的,在此類中對外提供明確參數類型的接口,接口內部通過performTarget
方法調用服務方組件的Target
、Action
。由於CTMediator
類的調用是通過runtime
主動發現服務的,所以服務方對此類是完全解耦的。
但如果CTMediator
類對外提供的方法都放在此類中,將會對CTMediator
造成極大的負擔和代碼量。解決方法就是對每個服務方組件創建一個CTMediator
的Category
,並將對服務方的performTarget
調用放在對應的Category
中,這些Category
都屬於CTMediator
中間件,從而實現了感官上的接口分離。
casatwy組件化實現細節
對於服務方的組件來說,每個組件都提供一個或多個Target
類,在Target
類中聲明Action
方法。Target
類是當前組件對外提供的一個“服務類”,Target
將當前組件中所有的服務都定義在裏面,CTMediator
通過runtime
主動發現服務。
在Target
中的所有Action
方法,都只有一個字典參數,所以可以傳遞的參數很靈活,這也是casatwy提出的去Model
化的概念。在Action
的方法實現中,對傳進來的字典參數進行解析,再調用組件內部的類和方法。
架構分析
casatwy爲我們提供了一個Demo,通過這個Demo
可以很好的理解casatwy的設計思路,下面按照我的理解講解一下這個Demo
。
文件目錄
打開Demo
後可以看到文件目錄非常清楚,在上圖中用藍框框出來的就是中間件部分,紅框框出來的就是業務組件部分。我對每個文件夾做了一個簡單的註釋,包含了其在架構中的職責。
在CTMediator
中定義遠程調用和本地調用的兩個方法,其他業務相關的調用由Category
完成。
1 2 3 4 | // 遠程App調用入口 - (id)performActionWithUrl:(NSURL *)url completion:(void(^)(NSDictionary *info))completion; // 本地組件調用入口 - (id)performTarget:(NSString *)targetName action:(NSString *)actionName params:(NSDictionary *)params; |
在CTMediator
中定義的ModuleA
的Category
,對外提供了一個獲取控制器並跳轉的功能,下面是代碼實現。由於casatwy的方案中使用performTarget
的方式進行調用,所以涉及到很多硬編碼字符串的問題,casatwy採取定義常量字符串來解決這個問題,這樣管理也更方便。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #import "CTMediator+CTMediatorModuleAActions.h"
NSString * const kCTMediatorTargetA = @"A"; NSString * const kCTMediatorActionNativFetchDetailViewController = @"nativeFetchDetailViewController";
@implementation CTMediator (CTMediatorModuleAActions)
- (UIViewController *)CTMediator_viewControllerForDetail { UIViewController *viewController = [self performTarget:kCTMediatorTargetA action:kCTMediatorActionNativFetchDetailViewController params:@{@"key":@"value"}]; if ([viewController isKindOfClass:[UIViewController class]]) { // view controller 交付出去之後,可以由外界選擇是push還是present return viewController; } else { // 這裏處理異常場景,具體如何處理取決於產品 return [[UIViewController alloc] init]; } } |
下面是ModuleA
組件中提供的服務,被定義在Target_A
類中,這些服務可以被CTMediator
通過runtime
的方式調用,這個過程就叫做發現服務。
我們發現,在這個方法中其實做了參數處理和內部調用的功能,這樣就可以保證組件內部的業務不受外部影響,對內部業務沒有侵入性。
1 2 3 4 5 6 | - (UIViewController *)Action_nativeFetchDetailViewController:(NSDictionary *)params { // 對傳過來的字典參數進行解析,並調用ModuleA內部的代碼 DemoModuleADetailViewController *viewController = [[DemoModuleADetailViewController alloc] init]; viewController.valueLabel.text = params[@"key"]; return viewController; } |
命名規範
在大型項目中代碼量比較大,需要避免命名衝突的問題。對於這個問題casatwy採取的是加前綴的方式,從casatwy的Demo
中也可以看出,其組件ModuleA
的Target
命名爲Target_A
,被調用的Action
命名爲Action_nativeFetchDetailViewController:
。
casatwy將類和方法的命名,都統一按照其功能做區分當做前綴,這樣很好的將組件相關和組件內部代碼進行了劃分。