簡述組件化解決方案CTMediator與MGJRouter的主要思想

簡述CTMediatorgit

 
CTMediator按照功能的結構來說,使用時須要實現CTMediator的個三部分。
1.CTMediator類:承擔總樞紐,總調度的責任
2.Target_(ModuleName)類:承擔組件對外暴漏接口功能,組件要提供什麼服務,主要在它的接口聲明上進行體現
3.CTMediator+(ModuleName)分類:主要供客戶端使用,裏面聲明瞭能夠調用的組件接口。
下面詳細講解
 
Part1: CTMediator核心功能實現:
CTMediator主要採用target-action的方式實現組件間解耦合,自己功能徹底獨立,不依賴任何組件模塊。
主要結構以下:
CTMediator做爲中介者,是各個組件的進行信息通信的中樞。
主要實現方案分兩種狀況:
1.首先利用runtime進行反射,將類字符串和方法字符串轉換成類和SEL方法選擇子:
SEL action = NSSelectorFromString(@"Action_response:");
NSObject *target = [[NSClassFromString(@"Target_NoTargetAction") alloc] init];
而後調用cocoa touch框架提供的方法直接調用
代碼以下:
[target performSelector:action withObject:params];

 

2.或者使用cocoa touch提供的命令模式,將消息和消息接受者封裝成一個對象,進行執行。
首先,利用target-action生成方法簽名
而後,建立NSInvocation對象,進行執行invoke。並拿到返回的結果。
代碼以下:
利用方法簽名,NSInvocation實現
NSMethodSignature* methodSig = [target methodSignatureForSelector:action];
if(methodSig == nil) {
    return nil;
}
const char* retType = [methodSig methodReturnType];
if (strcmp(retType, @encode(void)) == 0) {
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
    [invocation setArgument:&params atIndex:2];
    [invocation setSelector:action];
    [invocation setTarget:target];
    [invocation invoke];
    return nil;
}

 

Part2: 組件對外服務接口
若是組件須要對外提供服務,就須要建立本身的接收動做類
好比ModuleA要對外提供服務。那麼就要建立一個
Target_A類,而後在Target_A類的.h文件中聲明對外服務的接口,並在.m文件中進行實現。
注意:Target_A類是依賴組件的。它屬於組件的一部分。
代碼以下:
@interface Target_Mine : NSObject
- (id)Action_nativeFetchSportsResultVC:(NSDictionary *)param;
- (void)Action_remoteAlertSportsResultVC:(NSDictionary *)param;
@end
@implementation Target_Mine
- (id)Action_nativeFetchSportsResultVC:(NSDictionary *)param {
    UIViewController *vc = [[FZMineCoordinator sharedFZMineCoordinator] targetVCWithClassName:NSStringFromClass([FZSportsResultVC class])];
    if ([vc isKindOfClass:[FZSportsResultVC class]]) {
        [(FZSportsResultVC *)vc configContent:param[@"title"]];
    }
    return vc;
}

- (void)Action_remoteAlertSportsResultVC:(NSDictionary *)param {
    UIViewController *vc = [[FZMineCoordinator sharedFZMineCoordinator] targetVCWithClassName:NSStringFromClass([FZSportsResultVC class])];
    if ([vc isKindOfClass:[FZSportsResultVC class]]) {
        [(FZSportsPlanVC *)vc configContent:param[@"title"]];
    }
    
    id<UIApplicationDelegate> appDelegate = [UIApplication sharedApplication].delegate;
    UITabBarController *rootVC = [[appDelegate window] rootViewController];
    [rootVC.childViewControllers[0] pushViewController:vc animated:YES];
}
@end

 

Part3: CTMediator+ModuleA組件通信實際使用類github

爲了實現徹底解耦,這個類全部使用的全部參數所有是cocoa touch框架中定義的基本類型。
像:NSDictionary,NSString, UIImage等。
裏面按照做用分,能夠分爲:
模塊名稱字符串,模塊本地調用方法名稱字符串,模塊遠程調用方法名稱字符串
在CTMediator+ModuleA分類文件的.h文件中,定義了供其餘模塊使用的接口
在CTMediator+ModuleA分類文件的.m文件中,實現供其餘模塊使用的接口,調用用CTMediator的runtime機制進行實現。
 
CTMediator提供的方案是我認爲最好的,巧妙的使用了cocoaTouch提供的反射機制,方法簽名與命令模式,簡單又完美的解決了組件間的解耦問題。
同時由於實現是基於Object-C的特性,穩定性靠譜。
在方案不一樣做用類分工上,簡單明瞭。實現了從形式到實質上徹底的解耦,同時提供了對外部appURL調用的支持。是很是完美的方案。
代碼以下:
- (IBAction)goSportsPlanDetail:(UIButton *)sender {
    UIViewController *vc = [[CTMediator sharedInstance] Mediator_fetchSportsPlanVC:@{@"title":[sender currentTitle]}];
    [self.navigationController pushViewController:vc animated:YES];
}
CTMediator提供的方案是我認爲最好的,巧妙的使用了cocoaTouch提供的反射機制,方法簽名與命令模式,簡單又完美的解決了組件間的解耦問題。
同時由於實現是基於Object-C的特性,穩定性靠譜。
在方案不一樣做用類分工上,簡單明瞭。實現了從形式到實質上徹底的解耦,同時提供了對外部appURL調用的支持。是很是完美的方案。
 
簡述MGJRouter
 
蘑菇街組件化方案,採用了url-block加protocal-class的方案,url-block用於頁面跳轉,protocal-class用於組件跳轉
下面對MGJRouter的主要思路進行分析。
 
MGJRouter核心功能實現
Part1:
MGJRouter的url-block實現方案思路爲,在路由中心維護着一張路由表,url爲key, block爲value。
註冊路由表時,將key和value對應保存到路由表routes中
使用時,根據URL拿到對應的block進行執行。
 
- (NSMutableDictionary *)routes
{
    if (!_routes) {
        _routes = [[NSMutableDictionary alloc] init];
    }
    return _routes;
}

可是URL對應像UIImage,NSData這樣的很是規對象是很難傳遞的。app

 
Part2:
蘑菇街的protocal-class實現方案思路爲:
在ModuleManager內維護着一張映射表,以protocol爲key,以Class爲Value。
註冊映射表
[ModuleManager registerClass:ClassA forProtocol:ProtocolA]

使用映射表框架

[ModuleManager classForProtocol:ProtocolA]
注意:上面一一對應的關係中,類是實現了對應的協議的。因此經過協議拿到的類是能夠按照protocol中聲明的方法自由使用的。
 
 
註冊步驟:
1.url-block方案註冊:
在模塊對應要展現的頁面中,在load方法中進行註冊
+ (void)load {
    [MGJRouter registerURLPattern:@"engineer://SportsPlanVC" toObjectHandler:^id(NSDictionary *routerParameters) {
        FZSportsPlanVC *planVC = [FZSportsPlanVC new];
        [planVC configContent:routerParameters[@"MGJRouterParameterUserInfo"][@"title"]];
        return planVC;
    }];
}
2.protocal-class方案註冊:
在模塊的協議實現類中進行註冊:
+ (void)load {
    [[FZProtocolMediator sharedFZProtocolMediator] registerProtocol:NSProtocolFromString(@"FZModuleMineProtocol") forClass:[FZModuleMineProtocolImplete class]];
}
 
使用步驟:
根據對應的單例獲取方式,獲取既可。
 
- (IBAction)mgj_goSportsPlanDetail:(UIButton *)sender {
    UIViewController *vc = [MGJRouter objectForURL:@"engineer://SportsPlanVC" withUserInfo:@{@"title":[sender currentTitle]}];
    [self.navigationController pushViewController:vc animated:YES];
}
- (IBAction)protocol_class_goSportsPlanDetail:(UIButton *)sender {
    Class<FZModuleMineProtocol> class = [[FZProtocolMediator sharedFZProtocolMediator] classForProtocol:NSProtocolFromString(@"FZModuleMineProtocol")];
    UIViewController *vc = [class fetchSportsPlanVC:sender.currentTitle];
    [self.navigationController pushViewController:vc animated:YES];
}
MGJRouter實現方案上有些複雜,使得新手學習上有些困難,同時兩張表也增長了維護成本。
不過不能否認的是url-block和protocal-class都是很是巧妙的解耦方案。
 
使用效果以下:

相關文章
相關標籤/搜索