模块解耦的三种方案

模块解耦的三种方案

Posted by Ted on August 26, 2019

1、URLRouter

URLRouter:将不同的模块定义成为不同的URL,通过URL的形式进行跨模块调用。

传递一串参数URL就可以进行页面间的跳转,通过分解URL的字段来获取要跳转的页面和携带的参数,指向不同的页面,也可以支持多级页面跳转。URL的通用性也适用于跨平台实现,iOS, Android,Flutter都可以按照URL来进行路由。

同时可以兼容APP间跳转URL Scheme进行进程间的通信,同App外面打开App中的某个页面。

当然这种方案缺点也是很明显的,基于URL的设计只适合与UI界面,功能性的模块是不能采用这种方案的,所以这种方案只适用于视图驱动的模块。

参考URL

img

根据URI进行拆分就能得到需要跳转的路径和参数

示例代码

    [URLRouter openRoute:@"dnfgamehelper://MomentModule/vc/MomentDetailViewController?momentId=10018&show=1" onVC:self handler:^(NSDictionary * _Nonnull callback) {
        
    }];

通过url可以获取要跳转的VC:MomentDetailViewController以及参数:momentId=10018&show=1

2、ProtocolClass

Protocol(协议)的声明看起来类似一个类的接口,不同的是Protocol没有父类也不能定义实例变量。Protocol是一种特殊的程序设计结构,用于声明专门被别的类实现的方法。因为OC是单继承的,由于不支持多继承,所以很多时候都是用Protocol和Category来代替实现多继承。Protocol只能定义公用的一套接口,但不能提供具体的实现方法。

Protocol的基本用途:

  • 可以用来声明一大堆方法(不能直接声明成员变量,但是利用setter和getter方法可以达到相同效果)
  • 只要某个类遵守了这个协议,就相当于拥有这个协议中的所有方法声明
  • 只要父类遵守了某个协议,就相当于子类也遵守了

原理:

img

3、Target-Action

利用OC的runtime能力,动态的调用指定Target的action.

核心代码

    Class cls = NSClassFromString(@"TargetClassName");
    id obj = [[cls alloc]init];
    SEL aSelector = NSSelectorFromString(@"doSomethingWithParam1:param2:");
    NSMethodSignature *sig  = [cls instanceMethodSignatureForSelector:aSelector];
    NSInvocation *msgInvocation = [NSInvocation invocationWithMethodSignature:sig];
    [msgInvocation setTarget:obj];
    [msgInvocation setSelector:aSelector];
    [msgInvocation setArgument:&para1 atIndex:2];
    [msgInvocation setArgument:&para2 atIndex:3];
    [msgInvocation invoke];
    [msgInvocation getReturnValue:&callBackValue];

原理如下

img

4、对比

URLRoute优点

  • 通过URL来请求资源。不管是H5,RN,Weex,Flutter、iOS、Android界面或者组件请求资源的方式就都统一了;
  • 服务器可以动态地控制页面跳转,对于一些业务变化比较快的应用很适合。

URLRoute缺点

  • Map规则是需要注册的,它们会在load方法里面写。写在load方法里面是会影响App启动速度的;
  • URL链接里面关于组件和页面的名字都是硬编码,参数也都是硬编码。 而且每个URL最好要有一个文档进行维护;
  • URL的参数传递是不够友好的,它最多是传递一个字典。

Target-Action优点

  • 充分的利用Runtime的特性,无需注册。
  • 每个category对应一个Target,Category中的方法对应Action场景。Target-Action方案也统一了所有组件间调用入口

Target-Action缺点

  • Runtime编译的时候无法报错,容易造成没有Selector的crash;
  • 每个Target去写一个Category编码量大。

ProtocolClass优点

  • 没有硬编码。Class的interface与Protocol类似,快速生成,对于已有项目的改造比较方便。
  • 传递参数类型无限制,调用方法就跟普通对象调用方法一样

ProtocolClass缺点

  • Protocol要在当前类向Manager进行注册(如果通过NSProtocolFromString硬编码维护不友好,且有一个固定内存来进行map),注册分散不好管理。没法做组件不存在时或者出现错误时的统一处理。
  • 与Protocol的原始定义不符合,从代码编程规范来看不友好。