一次组件化的实践

===============
更新:
1. mvvm 可以将网络层转移到ViewModel 层中,这样就不需要将网络层抽离了,因为本来就没和 控制器耦合。
2. 每次使用蜂巢的时候 控制器一定要实现 服务的协议,不然蜂巢会崩,还很难找到原因
3. 蜂巢方案 虽然分离了控制器业务的耦合,但是引入了protocol 协议的耦合。同时需要维护 协议表 ,当跳转的时候需要去协议表里面找 对应的协议,然后再进行跳转。对组件化的不好的地方就是引入了协议,当进行组件化的时候,如果不先引入protocol 那么组件pod 的时候 就无法编译通过,因此 要求在使用的时候 就已经把所有的模块都在Core 核心类注册了服务,写好了protocol。这点缺点也很明显。

===============
之前做过简单的弹框pod库。也简单的看过各路大神对组件化的一些理解。
demo也下载下来跑了一下,但没有动手去实践过。要做组件化,首先应该明白
组件化到底是什么,是为了什么而存在的。

随着app的业务需求越来越复杂化,一个app 可能包含登录模块,视频播放模块,然后是一些相关的业务类,而一个公司的登录模块很大的情况是不会有协议上的变动,最多就是换一下域名,
当需要些一个新的app的时候,我们就把旧的项目的登录模块抽离出来,拉进新项目里面。
视频模块也是一样的,一个视频播放可能有 视频列表,视频记录,视频点播 播放器控制等等,
新的项目也能够复用,就把视频播放相关的功能什么的都拖到新项目就好了。

按照以往的思路,所有的东西都封成view 层级,就可以给各个控制器使用了。抽离的时候只需要把view剥离出来,而不需要关心跳转的逻辑业务。

现在新的思路是要求把整个视频以及登录相关的控制器都分离开来,这样 做视频模块的成员只用不断的维护视频模块, 做登录相关模块的成员只用不断的维护登录模块。

这样的期望是非常好的。又适合现在app的开发模式,但有个绕不过去的问题,就是模块间的跳转。我们经常在某个页面中突然发现用户登录过期了,然后就present出来登录的界面,一般这个会让tabar 控制器去引用 登录界面的控制器,从而让登录界面始终覆盖在页面最上面。但有时候我们要求 a b c d e f 之间的跳转不按照顺序来, a 跳 b 跳转到c 到d 再 e 而同时要求b c d e 都又能跳转到a 界面,这时候 c d e 界面都得引用a的这个控制器了(当然有通过导航栏回到a控制器的方法,这里不讲这种特殊的例子),很大程度上的可能性是 a 其实是个另外的模块,和cde都没什么关系, 当需要把cde相关的功能转移到新的项目中时候,有两个选择,一个是去掉a所有的代码,二 是把a引入进来,两种方法的弊端都很明显, 第一个是导入了无关的内容,第二个的弊端是你要删掉很多无用的东西。很容易出错。

于是 ,组件化的方案都提出了中间层的管理方案,通过中间层来找到模块、并转发各个模块之间的消息传递,所以组件化的核心思想就是提出中间层。在提出中间层的一个很重要的选项就是尽可能的降低耦合度,oc语言中 能够降低耦合度的 无非是runtime protrcol 和 category 这几种,网上已经有很多种组件化的方案了,选择适合公司的组件化方案即可,不再比较各个方案的优劣了。

团队选用的是阿里的蜂巢方案,是用的协议的方式来提供组件间的通信,每个业务对应一个协议 ,只要创建一个协议,然后将协议和业务(控制器)关联在一起,就可以通过协议找到业务(控制器)。来进行跳转了。还是拿a 跳转到b业务来举例, 现在给b注册了一个协议c ,当a 需要跳转到b控制器的时候,不需要引用b的头文件, 只需要 引用c 这个协议文件 就好了 ,然后用蜂巢的管理类,就可以拿到c 对应的业务,再判断c 是否为UIviewcontroller、 如果是uiviewcontroller 就可以跳转了。这样,当我把a模块抽离出来,就不会需要引用b相关的全部内容了。唯一需要的就是c这个协议, 这个协议 我们放在核心层的注册服务模块里,后面再讲讲这个核心层。除此之外,a 需要把参数传递给b 的时候,我们可以把方法和参数都写在c的协议里面,b 会实现协议的方法,就能够实现参数的传递了。反过来说,b 让a 做的事情,就可以注册a的协议,把参数方法都传递给a的协议即可。

当然阿里的这套方案不能解决全部的问题,一个很明显的问题 ,就是参数传递都是正向的,当我们希望逆向传递数值的时候,蜂巢的方案并没有提供解决思路,但逆向传值又是业务中经常出现的部分,所以开始寻找相关的解决方案。最后用的是 使用Routable后的思考 这篇来解决的。解决思路是给NSObeject 添加一个分类,
给分类用runtime添加一个delegate对象,delegate对象遵循某个协议,这个协议里面写具体的方法和内容,当b 想把消息回传给a的时候,只需要添加这个分类,就可以告诉通知代理去处理了。a作为delegate对象,去实现代理的方法,就实现了反向传值。

业务层所需要考虑的基本就是这些,还需要考虑的就是基类层 和核心层,先说基类层,为什么要存在基类层呢,拿控制器来举例,最常见的操作就是导航栏跳转后对导航条的设置,对分栏控制器的设置,是否要隐藏分栏控制器,导航条左右返回按钮是否需要处理等等,如果不做统一的管理,就必须在每个控制器里面写上是否隐藏,是否修改等等,与其在所有的页面里面一遍一遍的写,不如抽离一个基础类出来,减少业务类的代码量,子类只需要设置显示和隐藏的bool值,基类控制器就会在生命周期中管理了,也便于维护跳转等等。至于和业务无关的东西,是否需要旋转之类的,这些都写分类实现,原因是基类不强求使用,如果基类要用的直接放在基类里面就行了。其他的业务类根据需要添加分类就好了。我暂时是写了导航栏的基类,控制器的基类,还有分栏控制器的基类。

然后是核心类, 核心类包含哪些东西呢,可以说每个业务模块可能用到的部分都属于核心类,
拿网络层来说,页面需要网络数据,网络数据都会分散在各个模块里面,如果分散到业务层里面
。可能a 和b 模块都要登录接口,那就麻烦了,到时候很难拆开 登录接口了,所以就放在核心层里面,业务层需要继承基类层,同时要引入核心层的部分,当然那些注册的服务也是核心层的组成。

还是拿网络层来举例,到底一个怎样的网络层架构 适合组件化的管理。我们知道两点,一是网络层很难解耦合,而是网络请求数据到底给业务层怎样的数据 合适,我认为是写统一的请求接口,统一的参数接口,统一的请求成功,统一的请求失败,然后让成员自己去找这些方法来处理,但是每个接口又都不一样,怎么统一呢,那就只能继承了。所有的方法回传的数值都是接口模型本身,里面存储了你上传的数据 和你返回的数据,父类只是一个做这些事情的类,子类继承父类后填写上参数 和网址什么的,当控制器引用子类的属性并且作为子类的代理, 发起请求的时候,回应的消息 会通过 代理回传给控制器,就会统一在代理方法里面进行处理了,这时候就可以判断 这个返回的对象 是不是子类那个对象,如果是,代表找到 了对应的请求,就完成了网络层的处理,
在迁移的过程中,也变得更加容易,因为你调用了新的api 就是调用了新的子类而已,把旧的子类调用方法注释了,在返回的结果里面增加新的if类型就可以了。这里当然还是用的iOS应用架构谈 网络层设计方案大神的方案,基本上他把每个方面都考虑全了,我们只是引用了这种请求返回的接口设计思路,把这一部分拆分出来而已

核心层当然还有一些其他的处理。比如说数据存储,大神的下一篇文章也是讲的数据存储的部分。目前我们还没做这一块。

以上就是我们对组件化的框架完成的实践,并作为新项目的框架思路。有个需要转变思路的地点是pod化,组件化的方案最后都会把每个组件变成pod ,但我认为在项目初期最好不要太早做pod化。一方面这样可以减少处理难度,当后期组件功能比较完善的并且组件比较成熟的情况下,再做pod 也不迟。

还有一点就是组件内部自己的消息传递和跳转 没必要使用路由,原因是组件内部本来就是耦合在一起的,没有必要增加额外的开支。

.

猜你喜欢

转载自blog.csdn.net/github_35041937/article/details/78065426