简述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)) == ) {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
[invocation setArgument:&params atIndex:];
[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[] 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都是非常巧妙的解耦方案。
 
使用效果如下:

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

  1. Lightning Web Components 来自salesforce 的web 组件化解决方案

    Lightning Web Components 是一个轻量,快速,企业级别的web 组件化解决方案,官方网站也提供了很全的文档 对于我们学习使用还是很方便的,同时我们也可以方便的学习了解salesf ...

  2. 三. Vue组件化

    1. 认识组件化 1.1 什么是组件化 人面对复杂问题的处理方式 任何一个人处理信息的逻辑能力都是有限的,所以当面对一个非常复杂的问题时我们不太可能一次性搞定一大堆的内容. 但是我们人有一种天生的能力 ...

  3. iOS应用架构谈 组件化方案

    转载: iOS应用架构谈 组件化方案 简述 前几天的一个晚上在infoQ的微信群里,来自蘑菇街的Limboy做了一个分享,讲了蘑菇街的组件化之路.我不认为这条组件化之路蘑菇街走对了.分享后我私聊了Li ...

  4. iOS 组件化 —— 路由设计思路分析

    原文 前言 随着用户的需求越来越多,对App的用户体验也变的要求越来越高.为了更好的应对各种需求,开发人员从软件工程的角度,将App架构由原来简单的MVC变成MVVM,VIPER等复杂架构.更换适合业 ...

  5. iOS组件化思路 <转>

    随着应用需求逐步迭代,应用的代码体积将会越来越大,为了更好的管理应用工程,我们开始借助CocoaPods版本管理工具对原有应用工程进行拆分.但是仅仅完成代码拆分还不足以解决业务之间的代码耦合,为了更好 ...

  6. iOS开发之组件化架构漫谈

    前段时间公司项目打算重构,准确来说应该是按之前的产品逻辑重写一个项目.在重构项目之前涉及到架构选型的问题,我和组里小伙伴一起研究了一下组件化架构,打算将项目重构为组件化架构.当然不是直接拿来照搬,还是 ...

  7. iOS组件化思路-大神博客研读和思考

    一.大神博客研读 随着应用需求逐步迭代,应用的代码体积将会越来越大,为了更好的管理应用工程,我们开始借助CocoaPods版本管理工具对原有应用工程进行拆分.但是仅仅完成代码拆分还不足以解决业务之间的 ...

  8. 蘑菇街 App 的组件化之路

    在组件化之前,蘑菇街 App 的代码都是在一个工程里开发的,在人比较少,业务发展不是很快的时候,这样是比较合适的,能一定程度地保证开发效率. 慢慢地代码量多了起来,开发人员也多了起来,业务发展也快了起 ...

  9. iOS 组件化方案

    概述 近一年iOS业界讨论组件化方案甚多,大体来说有3种. Protocol注册方案 URL注册方案 Target-Action runtime调用方案 URL注册方案据我了解很多大公司都在采用,蘑菇 ...

随机推荐

  1. 数据库选项--ALTER DATABASE WITH 选项

    指定当数据库从一种状态转换到另一种状态时,何时回滚未完成的事务. 如果终止子句被忽略,则当数据库中存在任何锁时,ALTER DATABASE 语句将无限期等待. 只能指定一条终止子句,而且该子句应跟在 ...

  2. .NET中的FileUpload控件的使用-原生JS(二)

    本篇使用原生JS进行数据传输,使用FileUpload控件上传文件,适配IE. HTML <div class="container"> <div class=& ...

  3. 【C#进阶】委托那些事儿(二)

    二.传统的委托 接下来讲一讲方法参数.下面以“餐馆服务员为客户下单”[2]的事件作为描述.一般对事件的做法分3个部分: 1. 方法参数 EventArgs,一般用于传送数据.在本例场景中 public ...

  4. sqlserver学习

    清空数据表: delete from TableName  清除表中的所有的数据,保留表的结构 truncate table TableName 清除表中所有行,保留表结构 (重置ID) 删除表 Dr ...

  5. mysql数据库binlog日志的异地备份

    MySQL数据库的二进制日志binlog记录了对数据库的全量DDL和DML操作,对数据库的point to point灾难恢复起着无法替代的关键作用.因此,基于此类考虑,需要对生产环境产生的binlo ...

  6. CodeChef TWOROADS(计算几何+拉格朗日乘数法)

    题面 传送门 简要题意:给出\(n\)个点,请求出两条直线,并最小化每个点到离它最近的那条直线的距离的平方和,\(n\leq 100\) orz Shinbokuow 前置芝士 给出\(n\)个点,请 ...

  7. Ultra-QuickSort (POJ 2299)树状数组+离散化

    题目链接 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm ...

  8. CDN添加流程

    CDN的全称是Content Delivery Network,即内容分发网络.其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快.更稳定.通过在网络各处放置节 ...

  9. gitlab改变服务器ip

    一./home/git/gitlab/config/unicorn.rb 其中的ip需要修改,否则unicorn无法启动. 二./home/git/gitlab-shell/config.yml 其中 ...

  10. 怎么在Win7系统清除DNS缓存和刷新DHCP列表

    如何清除DNS缓存?开始-运行,如下图所示: 2 在谈出的对话框中输入“cmd”,如下图所示: 3 在出现的DOS命令窗口输入“ipconfig /flushdns”,然后就清除DNS缓存了,在我们遇 ...