简介
- 定位:统一的“配置能力注册与治理”基础设施,提供类型安全的 Provider 契约、依赖/冲突建模、拓扑初始化与状态流分发,面向全应用各业务模块复用。
- 核心目标:
- 类型安全:以
IFeatureConfigProvider/FeatureState为强约束,编译期可检查。 - 一致性:依赖/冲突统一在注册层校验,初始化顺序经拓扑排序保证。
- 可扩展:模块化注册,多仓库并行。
- 落地路径:为模块定义
ConfigModule→ 在仓库XxxRepository中注册 Provider → 调用initializeAsync()→ 消费者订阅所需状态流。
设计初衷与要解决的问题
- 统一配置能力,减少重复实现:历史上各模块各自实现开关/选项,规则分散、风格不一,难以复用与治理。
- 显式建模依赖/冲突:跨模块特性耦合与互斥关系长期隐式存在,容易产生不可预期的组合与状态震荡。
- 可验证的初始化顺序:启动/懒加载阶段并发初始化易引发竞态与“未注册先读”,需要确定性顺序与校验壁垒。
- 类型安全与可观察性:弱类型配置与随意写通道导致运行时错误与状态不同步,需要强契约与可订阅状态流。
架构总览(mermaid)
注册生命周期与时序
Provider 契约(最小必要)
IFeatureConfigProvider:isFeatureEnabled():特性可用性(资源/渠道/策略)getDependencies()/getConflictsWith():显式依赖与互斥关系stateFlow: StateFlow<FeatureState>:特性当前状态
BaseFeatureConfigProvider<TState : FeatureState>:initDefaultValue():默认值恢复/迁移onConfigStateUpdated(newState):状态变更后的副作用(持久化/系统调用)updateConfigState { ... }:安全更新状态的唯一入口
示例(简化):
接入清单(Onboarding Checklist)
- 定义
ConfigModule:模块标识、依赖模块、Provider 列表。
- 建立
XxxRepository:继承BaseConfigRepository,在initializeAsync()时注册模块。
- 实现 Provider:选择合适基类;声明依赖/冲突;实现默认值恢复与副作用。
- 消费者订阅:按需订阅
stateFlow或查询仓库接口。
- 配置可视化与校验:在集成/预发阶段生成依赖图与分析报告。
关键校验与初始化要点
- 循环依赖检测:DFS + 递归栈,防止初始化死锁。
- 必要性:若不提前检测,将在初始化/订阅阶段形成死锁或不可达状态,定位成本高。
- 依赖完整性验证:保证所有声明依赖均已注册,缺失即终止。
- 必要性:缺失依赖会使拓扑不可解并引发运行时崩溃/降级失效,需在注册期阻断。
- 冲突检测:检测互斥 Provider 同时启用的冲突并按策略回退或报错。
- 必要性:避免运行期出现互斥功能同时开启造成 UI/逻辑抖动与状态反复回滚。
- 拓扑排序:Kahn 算法确定初始化顺序,先依赖后依赖者。
- 必要性:为并发初始化提供确定性序,消除竞态与“未注册先读”。
- 初始化策略:
- BaseFeatureConfigProvider:
featureEnableConfigCheck()更新启用态。 - SwitchFeatureConfigProvider:
initDefaultValue()恢复/设置默认值并同步。 - 必要性:统一默认值恢复与启用校验的时序与入口,保证状态幂等与可重复。
最佳实践与扩展
- 设计:职责单一、依赖合理、通过资源/BuildConfig 控制 enable。
- 性能:避免 Provider init 中的重 IO/CPU;按需懒加载;合并状态时去抖与背压。
- 错误处理:提供默认行为与重试路径,详尽日志;失败可回滚。
- 测试:覆盖注册/依赖/冲突/失败场景的单元测试。
- 添加新 Provider:继承基类 → 实现抽象方法 → 加入注册列表 → 定义依赖/冲突。
错误处理要点
- 模块重复注册:记录 warn,忽略重复保留首次。
- 模块缺失依赖:初始化超时或失败,抛出全局初始化异常。
- Provider 循环依赖/缺失依赖:终止注册完成流程并输出问题清单。
- Provider 冲突同时启用:按策略回退或报错并提示不可达状态。
- Provider 初始化异常:标记
loadingState=FAILED,供上层兜底与重试。
API 速查(精选)
FAQ 精选
- Q: 两个 Provider 互相声明冲突怎么办?
- A: 注册阶段会报告;选择“主导 Provider”回退从属。
- Q: UI 如何感知全局初始化失败?
- A: 订阅
Repository.loadingState,FAILED 显示兜底 UI 并提供重试。
- Q: 如何在 Application 级预热?
- A: 可在
App.onCreate预热关键模块,但注意冷启动成本,推荐按需初始化。
- Q: 如何做跨构建变体的特性屏蔽?
- A: 在 Provider 中使用资源布尔与
BuildConfig判定 enable,禁止 UI 写分支。
- Author:CoderWdd
- URL:https://www.wuinsights.top//article/17d77f2a-5e06-4085-aea6-1615fce62569
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts