随着业务越来越复杂,我们封装的组件越来越多,要是封装的粒度拿捏不准,就会出现大量组件之间耦合度高的问题。组件的粒度可以随着业务的调整,不断的调整组件职责的划分。但是组件之间的调用依旧不可避免,相互调用对方组件暴露的接口。如何减少各个组件之间的耦合度,是一个设计优秀的路由的职责所在。
路由是组件化的中间件技术,他解决了我们组件化的耦合问题,它的存在使我们空间隔离组件成为可能。

举个栗子: 当我们想跳转一个A页面的时候,通常来讲我们需要import A页面的头文件,在写相应的跳转方法,但是这样,我们就耦合了A文件,也就无法与之独立,如果A页面是其他业务的文件,那么我们将与其他业务耦合,这样千丝万缕的联系,使我们整个工程根本无法独立拆分。

传统路由方式-JLRouter

JLRouter是比较稳妥的路由方案,他通过url映射block的方式,将行为和url进行连接,大多数的组件化工程都是基于这种路由方案进行的重构。这种方案简单易懂,但是要维护一个全局的url list,并且作为url的参数只能是简单类型,但是这些问题并不影响他发挥的作用。
这里就有很好的介绍文章:

https://www.jianshu.com/p/5d621b433c51

Target-Action的组件化方案-CTMediator

使用了一种新的Target-Action,完全解耦的,且可以传复杂参数,该方案是iOS OC语言的特性,充分利用了该语言最大的runtime特性,在运行期间确定调用的对象,完全解耦合,不需要任何list文件就能做到调用。

组件化技术选型的思考文章:

https://www.jianshu.com/p/afb9b52143d4

首先我们将各业务对外的接口封装成独立的库

而在接口中,我们都通过字典的方式进行传参,保证数据类型的多样性;另外我们直接在.h文件中采用markdown语法编写接口文档。

为什么用这种方式呢?我们考虑到文档和文件分离容易造成更新不一致的情况,我们希望尽量减轻开发人员的工作数量,而不是维护多个文件。通常,开发人员直接阅读.h文件即可,但当我们想生成文档的时候,我们只需要将内容拷贝到任意的markdown浏览器,即可以生成一份正式文档:

当我们对外接口编写完毕,我们只需要将这些接口以runtime的方式,连接到对应的方法上面,编译器认可这种运行时的处理方式,不会报错,这时,我们的接口和接口实现就解耦合了,而我们的调用方与实现方也基于此而拆分成功。
接口实现:

具体runtime的实现代码:

这短短的数十行核心代码,使得我们的方法调用通过runtime而解耦合。

最后

蘑菇街在一个项目里同时用了方案2和方案3两种方式,会让写组件的人不知所措,新增一个接口时不知道该用方案2的方式还是方案3的方式,可能这个在蘑菇街内部会通过一些文档规则去规范,但其实是没有必要的。可能是蘑菇街作为电商平台一开始就注重APP页面间跳转的概念,每个模块已经有一个对应的URL,于是组件化时自然想到通过URL的方式表示组件,后续发现URL方式的限制,于是加上方案3的方式,这也是正常的探索过程。
上面论述下方案1确实比方案2+方案3简单明了,没有 注册表常驻内存/参数传递限制/调用分散 这些缺点,方案1多做的一步是需要对所有组件方法进行一层 wrapper,但若想要明确提供组件的方法和参数类型,解耦统一处理,方案2和方案3同样需要多加这层。
实际上我没有组件化相关的实践,这里仅从 limboy 和 casa 提供的这几个方案对比分析,我还对组件化带来的收益是否大于组件化增加的成本这点存疑,相信真正实践起来还会碰到很多坑,继续探索中。

路由方案