简述组件化解决方案CTMediator与MGJRouter的主要思想

简述CTMediator

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组件通讯实际使用类

为了实现完全解耦,这个类所有使用的所有参数全部是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这样的非常规对象是很难传递的。

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都是非常巧妙的解耦方案。

使用效果如下:

demo地址为:https://github.com/zhfei/Engineer

原文地址:https://www.cnblogs.com/zhou--fei/p/10306657.html

时间: 2024-11-08 11:05:39

简述组件化解决方案CTMediator与MGJRouter的主要思想的相关文章

Gradle自动实现Android组件化模块构建

背景 随着App的不断迭代,业务会变得越来越复杂,业务模块会越来越多,且每个模块的代码也会变得越来越多.为了应对这一场景,我们需要把不同的业务模块划分成一个个组件,在修改业务代码的时候只需要在对应模块修改就可以了.通过高内聚,低耦合的业务模块来保证工程的健壮性和稳定性.现在问题来了,当组件的数量变得越来多的时候,我们如何管理业务组件呢? 原创声明: 该文章为原创文章,未经博主同意严禁转载. 为什么我们要用Gradle管理组件呢? 先来看看Android组件化需要实现的目标.(什么是组件化构建?)

微信小程序组件化(上)

小程序对组件化的"支持"情况 微信小程序(以下简称"小程序",版本)虽然默认定义了很多有用的组件,但是在开发小程序过程中,往往需要自定义业务组件.而小程序开发者文档中却未对自定义组件给出很好的解决方案或示例. 猜其原因可能有两方面: 从小程序开放的API来看,它去除了DOM和BOM,视图与数据层交互采用简单的单向数据绑定和事件绑的形式.可能其初衷是想降低开发难度和学习门槛,尽量减少概念. 小程序推出时间不到一年,这些功能可能还在完善中. 自定义组件的难点 微信的组件

什么是组件化

人面对复杂问题时候的处理方式任何一个人处理信息的逻辑能力都是有限的所以,当面对一个复杂的问题时,我们不太可能一次性搞定一大堆的内容但是,我们人有一种天生的能力,就是将问题拆解,如果讲一个复杂的问题拆分成很多个可以处理的小问题,在将其放在整体当中,你会发现大的问题也迎刃而解, 组件化也是类似思想 如果我们将页面中所有逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理和拓展但如果我们将页面拆分成一个个小的功能块,每功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就会变得

Vue 认识组件化

组件化开发 什么是组件化 如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展. 但如果,我们讲一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了 组件化思想 组件化是Vue.js中的重要思想 它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用 任何的应用都会被抽象成一颗组件树 组件化思想的应用: 有了组件化的思想,我们在之后的开发中就要充分的利用它 尽可能

iOS 组件化方案

概述 近一年iOS业界讨论组件化方案甚多,大体来说有3种. Protocol注册方案 URL注册方案 Target-Action runtime调用方案 URL注册方案据我了解很多大公司都在采用,蘑菇街 App 的组件化之路(http://limboy.me/tech/2016/03/10/mgj-components.html)蘑菇街的Limboy在这篇博客中做了很详尽的阐述 Target-Action runtime调用方案Casa在 iOS应用架构谈 组件化方案(http://casatw

蘑菇街 App 的组件化之路

在组件化之前,蘑菇街 App 的代码都是在一个工程里开发的,在人比较少,业务发展不是很快的时候,这样是比较合适的,能一定程度地保证开发效率. 慢慢地代码量多了起来,开发人员也多了起来,业务发展也快了起来,这时单一工程开发模式就会显露出一些弊端 耦合比较严重(因为没有明确的约束,「组件」间引用的现象会比较多) 容易出现冲突(尤其是使用 Xib,还有就是 Xcode Project,虽说有 脚本 可以改善) 业务方的开发效率不够高(只关心自己的组件,却要编译整个项目,与其他不相干的代码糅合在一起)

iOS开发之组件化架构漫谈

前段时间公司项目打算重构,准确来说应该是按之前的产品逻辑重写一个项目.在重构项目之前涉及到架构选型的问题,我和组里小伙伴一起研究了一下组件化架构,打算将项目重构为组件化架构.当然不是直接拿来照搬,还是要根据公司具体的业务需求设计架构. 在学习组件化架构的过程中,从很多高质量的博客中学到不少东西,例如蘑菇街李忠.casatwy.bang的博客.在学习过程中也遇到一些问题,在微博和QQ上和一些做iOS的朋友进行了交流,非常感谢这些朋友的帮助. 本篇文章主要针对于之前蘑菇街提出的组件化方案,以及cas

iOS 组件化架构漫谈

组件化架构漫谈 前段时间公司项目打算重构,准确来说应该是按之前的产品逻辑重写一个项目.在重构项目之前涉及到架构选型的问题,我和组里小伙伴一起研究了一下组件化架构,打算将项目重构为组件化架构.当然不是直接拿来照搬,还是要根据公司具体的业务需求设计架构. 在学习组件化架构的过程中,从很多高质量的博客中学到不少东西,例如蘑菇街李忠.casatwy.bang的博客.在学习过程中也遇到一些问题,在微博和QQ上和一些做iOS的朋友进行了交流,非常感谢这些朋友的帮助. 本篇文章主要针对于之前蘑菇街提出的组件化

组件化架构[转]

转自:https://www.jianshu.com/p/67a6004f6930 这两天更新了一下文章,并且做了一个PDF版的<组件化架构漫谈>,放在我Github上了.PDF上有文章目录,方便阅读,下面是地址. 如果你觉得不错,请把PDF帮忙转到其他群里,或者你的朋友,让更多的人了解组件化架构,衷心感谢!?? 组件化架构PDF Github地址 : https://github.com/DeveloperErenLiu/ComponentArchitectureBook 前段时间公司项目打