一、概念了解
1、组件化
就是**”基础库”或者“基础组件”,**意思是把代码重复的部分提炼出一个个组件供给功能使用。
使用:Dialog,各种自定义的UI控件、能在项目或者不同项目重复应用的代码等等。
目的:复用,解耦。
依赖:组件之间低依赖,比较独立。
架构定位:纵向分层(位于架构底层,被其他层所依赖)。
2、模块化
就是**”业务框架”或者“业务模块”**,也可以理解为“框架”,意思是把功能进行划分,将同一类型的代码整合在一起,所以模块的功能相对复杂,但都同属于一个业务。
使用:按照项目功能需求划分成不同类型的业务框架(例如:注册、登录、外卖、直播…..)
目的:隔离/封装 (高内聚)。
依赖:模块之间有依赖的关系,可通过路由器进行模块之间的耦合问题。
架构定位:横向分块(位于架构业务框架层)。
3、总结
其实组件相当于库,把一些能在项目里或者不同类型项目中可复用的代码进行工具性的封装。
而模块相应于业务逻辑模块,把同一类型项目里的功能逻辑进行进行需求性的封装。
二、组件化的必要性/产生背景
1、产生背景:
所有模块代码都编写在一个项目中,在项目越来越大后,测试/使用某个模块或功能,需要编译运行整个项目,麻烦。
2、组件化思路:
将每个模块作为一个组件,加一个中间层来协调各个模块间的调用,所有的模块间的调用都会经过中间层中转。(只让其他模块对中间层产生耦合关系,中间层不对其他模块发生耦合。)
3、组件化好处:
业务划分更佳清晰,新人接手更佳容易,可以按组件分配开发任务。
项目可维护性更强,提高开发效率。
更好排查问题,某个组件出现问题,直接对组件进行处理。
开发测试过程中,可以只编译自己那部分代码,不需要编译整个项目代码。
方便集成,项目需要哪个模块直接通过CocoaPods集成即可。
三、组件化设计思路1:有管理中心
完整的项目:https://github.com/dvlproad/033-Data-Notification-iOS
1、核心思想
启动时候注册关系表,执行时候遍历关系表
1 | // 核心思想1:注册,以统一管理,后续调用时候,从注册表中查询并执行对应的操作 |
2、实现方案
2.1、方案1:Url+block 路由器
缺点:入参,取参不明显。
2.2、方法2:protocal - class
哈希的本质 哈希冲突的解决:链地址法和开放寻址法。
问:使用多代理模式实现一个类似通知的功能,请问应该用什么来什么结构来存储代理和类的结构?
答:在多代理(Multiple Delegates)模式下,要存储多个代理对象,并且这些代理对象通常是弱引用,以防止循环引用。实现一个类似通知的功能,可以考虑使用 NSPointerArray 或 NSMapTable 来存储代理对象。如果你只是想管理多个代理对象,NSPointerArray 是更简单的选择。如果你需要将某个对象(如 UIViewController)与多个代理进行关联,NSMapTable 更合适,所以我们选择 NSMapTable 。
将要执行的方法统一放到类中,通过protocal或者类。
1 | // 根据 protocal 查找 class |
模块协议拆分为多个子协议,用户
网络处理协议、数据管理协议(单独)、用户界面更新协议
改进思想
1 | // 1、发起请求(LoginViewController) |
上述代码还可以演变成实现通知的一种形式(当注入的类中,有多个类都遵循了(实际上不应该出现)模块协议时候)
1 | // 1、发起请求(LoginViewController) |
下列图片来源于 《架构分层.graffle》 中的【三、模块间设计】
跳转的使用示例:
通知的实现示例:
跳转 + 数据变化后内部通知的实现示例:
四、组件化设计思路2:无管理中心
项目示例:CJStandardProject 中 CTMediator+CJDemoModuleMain.h
1、核心思想
核心思想:直接执行,让系统通过反射来找到要响应事件的类和方法
1 | void exec(target, action, params) { |
2、实现方案
2.1、方案1:CTMediator target+action+param
实现示例:

2.2、方案2:XXXService+Implemention

五、组件化实施过程的思考
1、架构分层
整个APP架构上从上到下分为三层,独立于APP的通用层,通用业务层,业务层。
1.1、独立于APP的通用层
此层常为:一些Cocoapods公有库或者自己编写的独立于APP的库。
举例:MJExtension、CJNetwork、分享、CJOverlayKit(Toast、HUD、ActionSheet)、CJShareList
1.2、每个APP自己的通用层
此层常为:前面的独立于APP的通用层的二次封装。若公司内部引用了第三方库,按照依赖倒置的原则,建议封装一层之后放到Basic Specs供业务方使用。好处:跟外部环境有效隔离,第三方库发生问题,公司内部可控。
如:CQNetwork、CQOverlayKit、CQShareKit、网络库CQNetwork、数据库(FMDB/WCDB)、缓存库等
依赖倒置原则告诉我们要面向接口编程;通过抽象(接口或抽象类)使各个类或模块实现彼此独立,互不影响,实现模块间的松耦合。
1.3、业务模块
业务层的模块应该按照模块化的设计思想,尽量做到高度的“高内聚,低耦合”。
因模块高度独立,且高频使用,若公司内部有多个App同时需要依赖,建议单独创建私有库Specs。


