第2章:离线分层架构整体蓝图:视图、分层结构、组件依赖、数据流向
2.1 架构总览
离线分层架构是Repository模式在资源受限、网络不稳定的终端或边缘场景下的核心落地形态。它将数据访问、缓存、离线同步与业务逻辑严格分离,使每一层只关注自身职责,并通过接口契约进行交互。
整体蓝图可抽象为四层模型:
- 视图层(View Layer) — 用户交互与UI状态管理。
- 服务层(Service Layer) — 业务编排、离线策略调度、数据一致性协调。
- 仓储层(Repository Layer) — 数据访问抽象、缓存策略、离线持久化。
- 数据源层(Data Source Layer) — 本地数据库、云端API、文件系统等具体存储。
各层之间仅允许上层依赖下层,禁止跨层直接调用或反向依赖,确保架构的单向依赖和信任链路可审计。
2.2 分层职责与边界
| 层级 | 核心职责 | 对外暴露的边界 |
|---|---|---|
| 视图层 | 渲染UI、收集用户事件、管理页面状态 | 调用服务层接口,不接触任何数据源 |
| 服务层 | 业务规则执行、离线策略判断(网络状态/缓存有效期)、数据合并与冲突处理 | 仅依赖仓储层抽象接口 |
| 仓储层 | 数据访问统一入口、多级缓存路由、离线写缓冲、数据同步策略 | 通过接口定义与数据源层解耦 |
| 数据源层 | 本地持久化(SQLite/LevelDB)、远程API调用、文件存储 | 实现仓储接口,内部可隔离 |
架构原则:每一层只感知下一层的抽象接口,不关注其具体实现。例如服务层不直接知道数据来自本地缓存还是远程API,从而允许仓储层灵活替换缓存算法或同步机制。
2.3 组件依赖关系
组件间的依赖采用接口注入方式,运行时通过依赖注入容器(如Dagger/Hilt、Kodein)组装。关键依赖链如下:
- Activity/Fragment → ViewModel → Service → Repository → DataSource
- Repository内部:CacheDataSource(内存/磁盘) + RemoteDataSource + LocalDataSource
- 离线同步器(SyncManager)作为服务层组件,依赖仓储层提供的同步接口
为防止循环依赖,严禁仓储层反向依赖服务层,也严禁数据源层引用视图层对象。
2.4 数据流向与控制流
离线读取流程(典型)
- 视图层发起数据请求 → 服务层判断是否需要刷新。
- 服务层调用仓储层
getItems(),不关心缓存策略。 - 仓储层按“先读内存缓存 → 未命中则读本地数据库 → 若还无数据则触发远程获取”的优先级路由。
- 远程获取成功后,仓储层更新本地数据库和内存缓存。
- 返回数据至服务层,最终推送至视图。
离线写入流程(典型)
- 视图层提交写操作 → 服务层校验业务规则。
- 仓储层将写操作先写入本地队列(离线写缓冲区),即刻返回成功。
- 后台同步器按策略(定时/网络恢复后)从队列取出操作,发送至远程API。
- 远程确认后,仓储层更新本地数据库并移除队列条目;若冲突,则触发合并回调。
关键决策:数据写回采用“写本地→异步同步”模式,保证用户操作即时响应,同时避免网络不可用时阻塞。仓储层内部维护一个操作日志用于冲突检测和幂等重放。
2.5 架构视图(SVG)
下方SVG图示展示离线分层架构的整体结构、组件分层、单向依赖箭头以及离线读/写数据流向。
2.6 选型权衡与风险点
| 权衡点 | 推荐方案 | 风险提示 |
|---|---|---|
| 缓存一致性 | 仓储层维护版本号,服务层在合并时检查 | 多端同时离线可能引发复杂冲突,需设计幂等合并策略 |
| 离线写缓冲区大小 | 使用固定队列(如100条),溢出时触发压缩 | 不合理设置可能导致内存OOM,建议持久化队列 |
| 同步粒度 | 按实体类型分别同步,而非全量 | 跨实体事务难以保证,需引入本地事务日志 |
| 数据源切换 | 仓储层通过策略模式动态选择数据源 | 频繁切换可能带来性能抖动,需预热连接池 |
常见反模式:视图层直接访问仓储层或数据源层。这破坏了分层规则,导致业务逻辑泄漏到UI、缓存策略难以替换。必须通过服务层作为中间层。
2.7 落地步骤与验收标准
落地步骤
- 定义仓储接口(Repository Interface),包含CRUD与会话无关的方法签名。
- 实现数据源层:本地数据库(如Room/Realm)、远程API(Retrofit/Ktor)。
- 构建仓储层实现:内存缓存+本地持久化+远程数据源的路由逻辑,以及离线写缓冲队列。
- 实现服务层:调用仓储接口,注入离线同步器,处理业务规则。
- 视图层通过依赖注入获取服务层实例,不再直接接触任何数据源。
验收标准
- 离线状态下,所有读操作返回本地缓存或本地数据库数据,无崩溃、无白屏。
- 离线状态下,写操作被安全放入本地缓冲队列,应用重启后不丢失。
- 网络恢复后,缓冲队列在30秒内触发同步,同步结果正确。
- 仓储层接口替换测试:更换本地数据库为文件存储后,服务层和视图层无需改动。
推荐工具:仓储层可使用
MapStore模式(类似kotlinx.collections.immutable)或现成的缓存框架(如Caffeine),但需确认其支持离线缓存生命周期管理。
2.8 信任链路与审计要点
每一层必须验证来自上层的输入参数,但信任链只能向下传递:
- 服务层信任视图层的调用意图(如用户已认证),但不信任数据有效性,需校验参数。
- 仓储层信任服务层提供的上下文(如用户ID),但不信任缓存条目是否过期,需检查TTL。
- 数据源层信任仓储层的查询参数,但不信任SQL注入风险,需使用参数化查询。
离线环境下的审计日志应当记录:数据获取来源(本地/远程)、缓存命中率、写缓冲队列长度、同步冲突次数,以支持后续架构调优。