前言
工程大了以后,就需要分拆,不管是组件化还是插件化,还是什么,解耦是第一步,而且是各个维度的解耦。
模块解耦合的方式
【1】Runtime 运行时调用
Class targetClass = NSClassFromString(@"TestViewController");
id instance = [[targetClass alloc]init];
//属性赋值
SEL sel = NSSelectorFromString(@"setImageName:");
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[instance performSelector:sel withObject:@"测试参数"];
#pragma clang diagnostic pop
[self.navigationController pushViewController:instance animated:YES];
/*
Runtime 这样的机制增加了程序的灵活性,可以通过给一个方法传递sel参数,
让这个方法动态的执行某一个方法,我们也可以通过配置文件制定需要执行的方法,
程序读取配置文件之后把方法的字符串翻译成sel变量然后给相应的对象发送这个消息。
*/
//当然属性的赋值还可以通过 KVC ,比上面的performSelector:sel 属性的set方法更方便!
[instance setValue:infoDic[attributeName] forKey:attributeName];
【2】接口隔离,机制与策略分离,面向接口调用
虽然说公共模块可以通过架构设计来避免耦合业务,但是业务模块之间还是会有耦合,而且这种情况是最多的,比如页面跳转啊,数据传递啊,这些情况前面的方法已经不够用了。那如何解耦不同业务模块之间的代码调用呢?
那就是面向接口调用,我们知道只要直接引用代码,就会有依赖,比如:
// A 模块
- (void)getSomeDataFromB {
B.getSomeData();
}
// B 模块
- (void)getSomeData {
return self.data;
}
那么我们可以实现一个 getSomeDataFromB 的接口,让 A 只依赖这个接口,而 B 来实现这个接口,这样就实现了 A 与 B 的解耦。
// 接口
@protocol BService <NSObject>
- (void)getSomeData;
@end
// A 模块, 只依赖接口
- (void)getSomeDataFromB {
id b = findService(@protocol(BService));
b.getSomeData;
}
// B 模块,实现BService接口
@interface B : NSObject <BService>
- (void)getSomeData {
return self.data;
}
@end
这样就可以实现了即满足了模块之间调用,也实现了解耦
协议与实现做成了一个机制与策略分离
所谓机制即是抽象出来的规则,比如:
f(x)=x^2 x属于R
所谓策略即是在具体场景中的应用,比如当x=2的时候:
f(2)=4 x=2
【3】中间件的路由通信解耦
A :推荐CTMediator 方式的组件化解耦
可以看我这篇文章:iOS组件化设计与开发
B:URL路由式组件化解耦
还有一种手段就是通过定义一套协议来实现模块间的通信,比如app里面的任何页面,或者任何操作都是通过一个URL来唤起的话,这样是不是就把各个复杂的业务之间解耦了呢,通信都使用URL.
为何如此URL(统一资源定位符)?
回到最开始我们描述的问题中第一点: 模块发现。其实也就是模块这种资源的定位问题,
这个和URL设计的初衷是不谋而合的。URL整套的设计思路就是在整体的互联网中解决信息孤岛,
让各个信息孤岛之间能够进行资源发现和资源调用而设计。而我们目前所要处理的模块间通信问题,
其实是这个宏大问题域的一个子集。因而选用URL协议,是一个非常顺理成章的事情。
可以方便地在页面之间构建高内聚和低耦合开发模式。他的核心思想是将每个页面视为一种资源,并通过标准URL协议(统一资源定位器)定位每个可访问的页面(资源)。