iOS 模块化与依赖方向
iOS 模块化与依赖方向
业务增长后,单一工程目标容易出现编译影响面大、代码跨业务引用和公共资源混乱等问题。模块化可以隔离变化,但拆成许多包并不会自动形成良好架构。模块边界应对应稳定业务能力,依赖保持单向,公共接口尽可能小。
一、从变化原因划分模块
常见模块类型包括:
- 应用装配:入口、场景和依赖组装。
- 业务功能:账户、订单、资讯等完整能力。
- 领域模块:模型与业务规则。
- 基础设施:网络、存储、日志和任务调度。
- 设计系统:颜色、字体、图标和公共组件。
边界来自团队所有权和变化原因,不应机械地为每个控制器创建模块。
二、保持依赖向内
业务功能可以依赖领域协议,基础实现则由应用层注入。领域规则不应引用具体页面和网络客户端。
public protocol AccountSession {
var currentUserId: String? { get }
var isSignedIn: Bool { get }
}
public final class SubmitOrderUseCase {
private let session: AccountSession
private let repository: OrderRepository
public init(
session: AccountSession,
repository: OrderRepository
) {
self.session = session
self.repository = repository
}
}
应用装配层提供实现,订单模块不需要知道账户页面和存储细节。
三、缩小 public 表面
模块内部控制器、数据实体和辅助类尽量保持内部可见。跨模块只暴露入口协议、稳定参数和结果类型。
public struct OrderDetailInput: Equatable {
public let orderId: String
public let source: OrderSource
}
public protocol OrderFeatureRouting {
func makeOrderDetail(input: OrderDetailInput) -> UIViewController
}
不要跨模块传递数据库对象或内部页面模型,这会把实现细节变成长期契约。
四、用协议打破反向依赖
账户模块不应为了打开订单页而直接依赖订单内部类型。可以由应用层实现路由协议,或通过协调器把两个功能装配起来。
协议应放在依赖方向合理的一侧。为每个类都创建协议会增加理解成本,只抽象真正需要替换或跨边界的能力。
五、避免万能 Core 模块
所有无法归类的代码都放进核心模块,会让它最终被所有功能依赖,也依赖大量基础组件,形成新的单体。
一段代码只有在语义稳定、被多个独立模块复用时才适合提取。偶然相似但未来变化原因不同的实现,可以暂时保留在各自业务中。
六、管理资源
颜色和组件优先来自设计系统模块,业务图片和本地化文本留在功能模块。资源名称使用项目约定前缀,避免合并冲突。
代码读取必需资源时,可以让缺失在开发阶段直接暴露,不用为每项资源添加不符合设计的随机默认值。
七、依赖注入集中在装配层
final class OrderFeatureFactory {
private let session: AccountSession
private let repository: OrderRepository
init(session: AccountSession, repository: OrderRepository) {
self.session = session
self.repository = repository
}
func makeSubmitUseCase() -> SubmitOrderUseCase {
SubmitOrderUseCase(session: session, repository: repository)
}
}
集中装配能清楚展示依赖图,也便于测试替换。业务内部到处读取全局单例会隐藏真实依赖。
八、控制跨模块事件
全局通知看似能消除依赖,过多后却让事件来源和顺序不可追踪。关键流程通过明确协议和调用链完成,一对多的全局事实才使用广播。
模块事件载荷只包含稳定领域值,不携带视图和上下文对象。
九、逐步迁移
模块化适合渐进实施:
- 绘制当前依赖关系。
- 选择边界清晰的功能。
- 定义最小公共契约。
- 保持行为不变地移动实现。
- 删除旧入口并验证构建与测试。
不要在移动模块的同时大规模改写业务,否则问题来源难以定位。
十、衡量模块化效果
观察指标包括:
- 小改动影响的编译范围。
- 跨业务导入数量。
- 公共接口大小。
- 循环依赖是否消失。
- 团队并行修改冲突。
- 单模块测试是否容易执行。
使用新的包管理或构建能力前,要确认项目最低系统和工具链兼容要求。
总结
iOS 模块化的目标是隔离变化。围绕业务能力划分模块,保持单向依赖,缩小公开表面,并由应用层集中装配实现。避免万能公共模块和全局事件总线,再用编译影响与协作效果验证拆分价值。
- 点赞
- 收藏
- 关注作者
评论(0)