iOS八股文之 组件化
一、组件化是啥
- 在软件代码设计中,有一个非常重要的判断好坏的标准是 “高内聚、低耦合”;那么组件化就是这个标准非常好的一个实践。
- 所谓高内聚,对应组件化纵向的分层以及每层基于特定功能进行组件拆分,每个组件专注于特定功能;所谓低耦合,组件间通过标准化接口通信,避免直接依赖;
- 组件化的核心挑战是组件间通信和依赖管理;
二、组件化的好处有啥
- 解耦代码:避免 “牵一发而动全身”(如修改一个功能导致多个模块报错);
- 团队并行开发:不同团队负责不同组件,通过接口约定协作,减少代码冲突;
- 按需编译:仅编译当前开发的组件,大幅提升编译速度;
- 功能复用:组件可在多 App 间复用(如车控组件同时用于不同子品牌App);
三、组件化方案收集
1. URL 路由式(蘑菇街 MGJRouter 为代表)
- 核心思想:通过 “URL 字符串” 作为通信介质,路由中心解析 URL 并转发到目标组件。
- 实现步骤:
- 注册阶段:组件在初始化时,向路由中心注册 URL 与处理函数的映射(如[router registerURLPattern:@“mgj://pay” handler:^(NSDictionary *params) { … }]);
- 调用阶段:调用方通过 URL 发起请求([router openURL:@“mgj://pay?amount=100” completion:^(id result) { … }]);
- 路由分发:路由中心解析 URL 的 “schema”(如mgj)、“path”(如/pay)和参数,找到对应的 handler 执行,并将结果通过 completion 返回。
- 核心技术:
字符串解析(URL 参数转字典);
注册表(通常用NSDictionary存储 URL→handler 的映射);
支持 Block 回调实现双向通信。 - 优缺点:
优点:接入简单、无编译期依赖(适合快速落地);
缺点:参数类型不安全(需手动转换)、URL 管理成本高(易冲突)、不适合复杂对象传递(URL 仅支持基本类型)。
2. 协议接口式(滴滴 DDComponentManager 为代表)
- 核心思想:通过 “协议(Protocol)” 定义组件接口,组件实现协议并注册,调用方依赖协议而非实现。
- 实现步骤:
- 定义协议:在公共模块(如CommonModule)中定义协议,声明组件提供的功能(如@protocol PaymentService - (void)payWithOrder:(Order *)order; @end);
- 组件实现协议:支付组件实现协议(@interface PaymentServiceImpl : NSObject … @end);
- 注册服务:组件启动时,向 “服务中心” 注册协议与实现类的映射([ServiceManager registerService:@protocol(PaymentService) withImplClass:[PaymentServiceImpl class]]);
- 调用服务:调用方通过服务中心获取协议实现(id payment = [ServiceManager getService:@protocol(PaymentService)]; [payment payWithOrder:order])。
- 核心技术:
协议(Protocol)作为接口契约;
服务中心(单例):管理协议→实现类的映射表,通过NSClassFromString反射创建实例;
依赖注入:服务中心可自动实例化实现类,或由组件手动注册实例。 - 优缺点:
优点:类型安全(编译期校验)、支持复杂对象传递、依赖关系清晰;
缺点:需维护协议层(增加代码量)、初期接入成本较高。
3. Target-Action 式(基于反射,蘑菇街后期优化方案)
- 核心思想:通过 “目标类(Target)” 和 “方法(Action)” 的字符串反射调用,避免直接依赖。
- 实现步骤:
- 定义 Target 类:每个组件提供一个Target_XXX类(如支付组件的Target_Payment),封装对外接口(- (void)action_payWithParams:(NSDictionary *)params);
- 调用方通过中间层反射调用:调用方不直接依赖Target_Payment,而是通过中间层(如Router)传递 “Target 名” 和 “Action 名”([Router invokeTarget:@“Payment” action:@“pay” params:@{@“amount”: @100}]);
- 中间层反射执行:Router通过NSClassFromString(@“Target_Payment”)创建实例,再通过performSelector:withObject:调用action_payWithParams:方法。
- 核心技术:
运行时反射(NSClassFromString、performSelector);
参数统一用NSDictionary传递(兼容任意类型);
中间层封装反射逻辑,避免调用方直接写反射代码。
优缺点: - 优点:无需协议层,组件解耦彻底;
缺点:类型不安全(字符串拼写错误编译期不报错)、反射有一定性能损耗(可通过缓存优化)。
4. 组合式(URL + 协议 + 依赖注入,美团 / 阿里方案)
大型项目通常采用组合式方案,兼顾多种场景:
- 页面跳转:用 URL 路由(简单直观);
- 服务调用:用协议接口(类型安全);
- 参数传递:结合依赖注入(自动解析复杂参数);
- 生命周期管理:增加组件管理器,统一处理初始化、降级、销毁。
四、组件化的其他关键技术点
- 依赖管理
私有 Pod:通过 CocoaPods 的私有仓库管理组件,组件间通过podspec声明依赖(如 A 组件依赖基础组件BaseModule);
源码依赖控制:禁止直接#import其他组件的非公开头文件,仅允许依赖公共接口层(协议 / 中间件)。 - 资源管理
组件私有资源:每个组件的图片、xib 等资源放在独立目录,通过bundle管理(如PaymentComponent.bundle);
资源路由:通过 “资源 URL”(如payment://image/pay_btn.png)访问组件资源,避免重名冲突。 - 组件生命周期
初始化:通过+load或组件管理器的setup方法,在 App 启动时初始化组件(注册路由 / 服务、预加载数据);
按需加载:非核心组件(如客服)可延迟初始化,在首次调用时再加载,减少启动时间;
降级策略:组件加载失败时(如网络错误),执行降级逻辑(如显示默认页面)。
