近几年组件化你们吵的沸沸扬扬的,它其实也不是什么黄金圣衣,穿上立马让你的小宇宙提高几个档次,也不是海皇的三叉戟,入手就能呼风唤雨,它不过就是一种app的架构思路。其实真的很简单,若是你的项目从发布之初就是用组件化,那么在开发的过程中势必会少不少麻烦,难点实际上是对咱们庞大古老的工程进行组件化的改造。设计模式
其实组件化说白了就是将一个单一的工程分解为各个独立的组件,而后按照某种方式任意组织成为一个拥有完整业务逻辑的工程。网络
举个例子你们就明白了,一辆完整的汽车历来都不是由一个工厂将全部的零部件生产完成的,而是轮胎厂生产轮胎,发动机厂生产发动机,玻璃厂生产玻璃等等,而后再组装成为一辆完整的汽车。咱们的各个组件或者说模块就是汽车的各个零部件,咱们的整个工程咱们也把它叫作宿主工程就是咱们的汽车,咱们按照必定的规则把他们拼装起来就是一个业务逻辑完整的工程。架构
那么组件化为什么应运而生,其实在咱们的开发过程当中,若是自己项目的规模不大,业务线比较少,人员也比较少,咱们使用通常的单一开发模式就行了。可是随着咱们的项目不断的迭代更新,业务线愈来愈多,发开人员也组件增多,这个时候就会暴露各类各样的问题app
耦合性严重框架
编译速度慢工具
测试不独立组件化
没法使用本身擅长的设计模式 ......布局
耦合性严重 关于耦合性严重这点举个你们深有体会的例子,咱们对接手二手甚至N手项目的时候都是深恶痛绝的,由于咱们不知道之前的开发人员的思路和架构,这个时候咱们每每面临着三类问题 1.代码的重构 2.增长新功能 3.改bug 就拿咱们改bug来讲,咱们因为不了解人家的思路,咱们把面前的bug改掉了,结果咱们出了更多得bug,越改越多,头疼至极,由于咱们可能将眼前bug改掉的同时,其余一样依赖改动地方的代码却不适用了,这就很是尴尬了。 一样地对咱们的新功能开发和代码重构也是如此,咱们好不容易将本身的功能模块搞定的时候,因为对老模块有依赖,一旦老模块中存在某些bug,会致使咱们整个工程都跑不起来,咱们不但测试不了本身新写的功能模块,并且咱们可能连bug在哪都不是一时半会儿就找到的,再加上解决的时间咱们将耗费大量的时间和精力,大大下降了咱们的发开效率。学习
编译速度慢 随着工程的业务线愈来愈多,发开人员不断增长,咱们的项目愈来愈庞大,每每项目编译少则一两分钟多则几分钟,虽然并不影响咱们的开发工做,可是咱们使用组件化的开发配合二进制化,咱们彻底能够提升整个项目的编译时间。测试
测试不独立
从这张图咱们能看到咱们在发开完毕咱们本身的模块以后,咱们须要对本身的模块进行测试,可是主工程里面的其余模块存在一个bug,致使咱们的工程编译不了,那么咱们开发的模块势必也是测试不了的,真的很尴尬。
没法使用本身擅长的设计模式 这个咱们稍微说一下你们应该能明白,若是你的公司主要是使用MVVM的架构模式进行开发的,而你只会使用MVC进行开发,是否是很尴尬,固然咱们能够按照MVC去套用MVVM进行开发,可是我给你们画一张图你们就明白了
假设说咱们的设计模式按照模块划分的话,咱们无法使用MVC去套用咱们的MVVM,这样咱们除了去学习MVVM以外别无他法,可关键是你真的有足够的时间在短期内上手吗? 固然若是咱们按照功能模块来划分的话,咱们的MVC却是能够套用咱们的MVVM,可是你能保证不出问题吗?
那么咱们使用组件化以后到底能达到什么样的效果呢?
功能组件: 包含控件(弹幕、轮播器、选项菜单、图文菜单等)、功能(断点续传、音频处理等)
业务组件: 业务线一(子业务线一,子业务线二.....) 业务线二(子业务线一,子业务线二.....)
组件层级之间的关系
从这张图咱们能够看出来,咱们三大组件类,实际上是有层级关系的,咱们的业务组件既要使用咱们的基础组件也要使用咱们的功能组件,它属于咱们基础组件和功能组件的上一层,而咱们的基础组件和功能组件属于同一层级,他们之间是不能互相产生依赖关系的。
若是说咱们的功能组件的弹幕须要使用到基础组件中的有关布局View的分类,咱们这个时候最好的作法并非将让咱们的功能组件依赖于咱们的基础组件,这样的话别人要使用咱们的弹幕却要将咱们整个基础组件都下载下来,那么咱们的组件化就失去了原有的意义。咱们在这里推荐的作法是讲咱们所须要的那块代码直接拷贝到咱们的功能组件当中去,这样作的好处在于咱们的功能组件不须要依赖咱们的基础组件。
一样在咱们三大组件类的内部,组件之间也不能产生依赖关系,比如咱们的弹幕不能依赖于咱们的播放器,总不能别人要使用咱们的弹幕还得把播放器给下载下来把,这样也是不合理的,对咱们业务组件也是同样的,咱们要增长或者删除某个业务线,结果致使其余的业务线无法正常的使用了,这都是不可取的。 可是某些时候咱们确实须要使用其余组件里面的内容,可是他们之间又不能产生依赖关系,这个时候咱们就要使用到组件间的通信,这个在后面会讲到组件间如何通信。
组件的存在形式 组件内部:根据设计模式划分文件夹结构 组件形式(对外):每一个组件都是以pod库的形式存在 组件测试:单独的测试工程(这里咱们能够经过建立pod模板库形式,直接拥有测试工程)
咱们是以Cocoapods的形式安装各个组件的
这张图咱们能够看到,咱们的业务组件是能够依赖咱们的基础组件和咱们的功能组件的,而咱们的业务组件都是以pod库的形式借助咱们Cocoapod安装到咱们宿主工程中去,咱们的宿主工程面向的都是咱们的业务组件。
组件间的通信 上面提到了咱们同层次间的组件或者是咱们三大组件内部的组件之间是不能有依赖关系的,可是确实有些时候咱们一个组件内部发生了一些事件想要告诉其余组件,或者须要调用某些组件的服务,这个时候咱们就须要用到组件之间的通信。 这里咱们来说讲其中的一种方式--中间件,咱们用一张示意图来描述一下
在这里咱们看到咱们组件都是经过中间件来进行交互的,组件将内部发生的变化告诉给中间件,中间件在通知其余组件。咱们组件把各自的服务给中间件,须要对应服务的组件就会去找中间件拿,这样的话咱们组件之间不会产生依赖关系,同时又能进行通信。
通常在组件化的分离各个组件的时候,解耦这个话题咱们是回避不了的,可是其实咱们通常会遇到两种状况 1.组件里面依赖其余公共功能 2.组件内部须要对接某个服务
组件里面依赖其余公共功能 对于这种状况,咱们通常最快的方式就是直接copy代码,虽然这个过程比较恶心,可是好处就是不会有额外的依赖,对于一些不重要的工具方法,咱们均可以拷贝到内部来使用。 举个例子你们都明白了,咱们使用获取屏幕尺寸的方法,而这个方法咱们通常写成宏定义放在咱们的基础组件中,咱们的业务组件中要用到这个方法没这个时候咱们不必把咱们基础组件也整个下载下来,咱们直接复制粘贴这短代码就行了。 咱们也能够把组件依赖的代码先作成一个pod库,而后依赖这个pod库就行了,这样咱们的问题就迎刃而解了。
组件内部须要对接某个服务 好比咱们控件的内部涉及到加载网络图片,咱们通常会用到咱们的SDWebImage的框架,虽然咱们能够在使用远程私有索引库的时候添加依赖,那么咱们在下载咱们的私有库里面组件的时候咱们能够将SDWebImage一并集成到咱们的宿主工程中。若是开发过程当中,公司用得不是SDWebImage不是会很尴尬吗? 因此咱们使用的方式就是使用block或者代理把这部分职责丢出去,那么咱们就能够自用的选择咱们所须要使用的第三方框架或者公司内部写的框架,不用再纠结了。