# 组件化、模块化、插件、子应用、框架、库理解 > 作为大前端时代下开发的我们,经常会被组件化、模块化、框架、库、插件、子应用等术语所迷惑。甚至有些人将组件化和模块化的概念混混为一谈。大量的博客和文章将这些概念混淆,误导了诸多读者。所以本文的目的主要是结合作者本人前后端、移动端等经验,谈谈这几个概念。 ## 组件 组件,最初的目的是为了**代码重用**。功能相对单一、独立。在整个系统结构中位于最底层,被其他代码所依赖。组件是 **“纵向分层”** ## 模块 模块,最初的目的是将同一类型的代码整合在一起,所以模块的功能相对全面、复杂些,但都同属于一个业务。不同模块之间也会存在相互依赖的关系,但大多数情况下这种相互依赖的关系只是业务之间的相互跳转。所以不同模块之间的地位是平级的。模块是 **“横向分块”** 因为从代码组织层面上讲,组件化开发是纵向分层,模块化是横向分块。所以模块化和组件化之间没有什么必然的联系。你可以将工程中的代码,按照功能模块进行逻辑上的拆分,然后将代码实现,按照模块化开发的思想,只需相应的代码按照**高内聚**的方式进行整合。假如一个 iOS 工程,使用 cocoapods 组织代码,将模块 A 相关的代码进行整理打包。 但是这样结果就是你的 App 工程虽然按照模块化的方式进行组织开发,那么某个功能模块进行修改或者升级的时候只需要修改相应模块的代码。假如个人中心模块和购物车模块都有数据持久化的代码。在不使用组件化开发的时候可能在2个模块的代码里面都有数据持久化的代码。这样一个地方有问题改动,另一个也要改动,这样工程组织方式不友好且代码复用率低。 那么在实际的项目中我们一般是组件化结合模块化一起开发的。 |类别| 目的 | 特点 | 接口 | 成果 | 架构定位 | |:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| |组件化|重用、解耦|高重用、低耦合|无统一接口|基础库、基础组件|纵向分层| |模块化|封装、隔离|高内聚、低耦合|有统一接口|业务模块、业务框架|横向切块| 参考: - https://blog.csdn.net/blog_jihq/article/details/79191008 - https://blog.csdn.net/blog_jihq/article/details/80669616 ![MVC架构](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2021-03-02-MVC.png) ![组件化结构](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2021-03-02-Components-Structures.png) - 各个组件彼此独立,互不影响。 - 组件通过组件管理器(也被叫做 ComponentManager、Router、MediumBus)通信。通过中介者进行通信。 - 公共库基础服务基本不变,所以需要下沉到公共组。所以这部分工作可以交给底层架构组到同学去做。 - 业务开发专心去做业务开发、业务流程的相关 ![组件化与传统架构对比](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2021-03-02-ComponentStructureComparation.png) - 左侧最基础的 MVC 架构 - 右侧是经过组件化之后的工程目录。 LianJiaClient 里面就是最基础的 AppDelegate,也就是 App 的启动入口。LJComponent 目录下按照彼此独立的功能拆分为多个组件。每个组件按照真实的物理文件夹,划分为多个工程文件夹,每个组件内部按照 MVC 组织,比如 UI、Model、Service、Logic、Connector - 工程文件和物理文件最好一一对应。好理解、好找 ## 如何实施组件化 1. 制定代码规范基础服务独立成库 什么叫公共基础组件?和业务无关的技术功能 ![组件抽取](./..assets/2021-03-02-ComponentPickUp.png) 2. 单个组件内部可以按照合适的架构组织,比如 MVC 和一些分层,比如 service ![单个组件结构示意图](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2021-03-02-SingleComponentStructure.png) 3. 组件之间通信包括2部分:组件之间页面跳转、组件之间服务的调用 - 页面跳转 url 导航去中心化。如果集中放到 Router 的导航方法内,则该方法可能会很长(n个组件,每个组件内m个页面,则需要 n*m 个组合)。每个业务组件,内部某个地方集中处理该组件内可能需要用到的注册 url 并返回对应的 vc,把 VC 返回给 ComponentManager,然后决定跳转方式(push、present) ![组件间互相访问](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2021-03-02-CompentsVisit.png) - 服务调用 ![组件通信代码](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2021-03-02-CompontentCommunicateCode.png) ![组件间服务通信](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2021-03-02-ComponentsVisitByService.png) 4. 进一步优化。动态性 ![组件通信 url 动态下发](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2021-03-02-ComponentURLViaNetwork.png) ComponentManager 在根据 lianjia://ModuleOverSeaHouseList 去匹配,然后发现有 url 则不跳转本地,直接打开 H5 5. 服务调用传递参数不方便。NSDictionary 组装很麻烦,可以将公共 Model 下沉,作为一个 Pod ![Model下沉](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2021-03-02-ComponentStructureModelInDeep.png) 6. 组件化架构 ![链家组件化架构](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2021-03-02-LianJiaComponentStructure.png) 7. 工程组织方式 ![链家工程化代码结构](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2021-03-02-LianJiaComponentProject.png) 8. 遇到的问题 ![image-20200816131719018](/Users/lbp/Library/Application Support/typora-user-images/image-20200816131719018.png) 重复资源问题:图标可以用 iconfont,并且可以控制颜色;或者在打包编译阶段,使用 shell、ruby 脚本去删除重复图片(局限性:只能图片名,对比像素比较麻烦) 9. 建议 ![链家组件化过程中遇到的问题](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2021-03-02-LianJiaComponentIssue.png) 10. 总结 ![组件化经验小结](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2021-03-02-ComponentTheory.png) Protocol:我遵循你这个组织的协议,则我就可以加入你这个组织,比如某个组件遵循协议,然后就可以统一调度管理。