从用户动作开始
收藏、阅读进度和展示偏好都属于轻量状态,但它们不能因为一次空值或旧格式数据而让页面失去可用的默认结果。
键空间与数据形状必须一起约束,避免同一个键被不同页面解释成不同对象。 这类边界放在组件内部后,页面只需要提交清晰的输入并消费结果,不必依赖某个临时控件的生命周期。
先定义可传递的状态
写入前统一 JSON 编码并在 flush 后返回,调用方不需要了解底层存储句柄。
import { common } from '@kit.AbilityKit';
import { preferences } from '@kit.ArkData';
export interface JsonCodec<T> {
encode(value: T): string;
decode(raw: string): T;
fallback(): T;
}
export class JsonStoreResult<T> {
ok: boolean;
value: T;
errorMessage: string;
constructor(ok: boolean, value: T, errorMessage: string = '') {
this.ok = ok;
this.value = value;
this.errorMessage = errorMessage;
}
}
export class JsonStoreCollection<T> {
key: string;
codec: JsonCodec<T>;
constructor(key: string, codec: JsonCodec<T>) {
this.key = key;
this.codec = codec;
}
}
export class JsonStoreOptions {
name: string;
flushAfterWrite: boolean;
constructor(name: string, flushAfterWrite: boolean = true) {
this.name = name;
this.flushAfterWrite = flushAfterWrite;
}
}
export class PreferencesJsonStore {
正常路径与失败路径共用边界
读取分支把缺失值、空字符串和解析异常都归一到调用者提供的 fallback。
type State02={ready:boolean;message:string};
function normalize02(value:string):State02{
if(value.length===0)return {ready:false,message:'使用默认结果'};
return {ready:true,message:value};
}
| Preferences JSON Store 的泛型边界 | 把输入与内部状态分离 | 状态可被下一步操作复用 |
| 重复动作 | 由统一入口处理 | 不遗留旁路结果 |
| 异常输入 | 回到可读的默认或提示 | 页面保持可用 |
把可观察结果留在正确一层
泛型只表达编译期意图,运行时仍要把 JSON 字符串当作不可信输入处理。

图中的流程用于说明组件内的责任切分:输入、状态转换与页面呈现分别有明确出口。
恢复逻辑不应依赖偶然顺序
迁移时先兼容旧字段,再在下一次写入时收敛成新的数据形状。
async function run02(input:string):Promise<void>{
const state=normalize02(input);
if(!state.ready)return;
// 调用方只接收确定的状态结果
}
接口的最小承诺
调用方需要的不是完整内部实现,而是稳定的输入、明确的返回状态和可预期的失败行为。Preferences JSON Store 的泛型边界 将这些承诺集中在导出 API 与数据模型之间,避免同一规则在多个业务页复制。
| 输入 | 接收被限定的数据 | 不猜测页面上下文 |
| 结果 | 返回可判断状态 | 不直接拼装业务页面 |
| 异常 | 提供可读失败信息 | 不把技术细节暴露给用户 |
集成时的检查顺序
接入方先确认公开入口和依赖版本,再用一组正常输入完成主题动作;随后使用空值、旧数据或重复操作验证恢复路径。只有结果仍可回读且页面保留继续操作的入口,组件边界才真正成立。
function recover02(error:Error):string{
const message=error.message.trim();
return message.length>0?message:'操作未完成,可继续尝试';
}
取舍与扩展
把 Preferences JSON Store 的泛型边界 做成独立组件,代价是需要维护稳定的类型与文档;收益是页面不再承担存储、手势、主题、系统回调或产物校验等跨页面规则。后续扩展应新增字段或策略,而不是绕过组件去修改既有状态。
| 数据或配置缺失 | 保留默认值 | 功能入口仍可使用 |
| 状态重复提交 | 单一状态入口 | 不产生冲突记录 |
| 依赖不满足 | 在集成前校验 | 停止在明确的错误边界 |
实施细节与验收边界
Preferences JSON Store 的泛型边界 的接入文档应当同时描述输入范围、状态变化、失败处理和恢复方式。正常结果不是唯一需要验证的分支:空值、重复触发、旧版本数据和依赖缺失都必须落回可解释的结果。对页面而言,最重要的是继续可操作;对组件而言,最重要的是每一次状态转换都有唯一来源。
组件升级时优先保持既有调用方式可用,再通过可选字段扩展能力。若需要改变默认行为,应当用显式参数声明,而不是依赖调用顺序或页面环境。这样多个项目同时接入时,定位问题可以回到接口契约,而不必在各自页面中追踪隐式条件。
验收可分为三层:先确认导出符号和依赖能够解析;再执行一次主题动作并回读结果;最后覆盖失败或重进场景,确认状态不会泄漏到下一次使用。三层都通过后,组件才具备稳定复用的基础。
在 耳畔三国·将星落 HarmonyOS OHPM 组件封装实战(02):Preferences JSON Store 的泛型边界 的接入过程中,输入、结果和恢复动作应当形成闭环。调用方提供的参数先经过组件边界的归一化,再进入确定的状态转换;任何无法解析、缺少依赖或重复触发的情况都不会把半完成结果留给页面。页面只依据组件返回的状态更新显示,因此用户能够在提示出现后继续调整输入或重新执行动作,而不是被迫退出当前上下文。
这套边界也便于后续维护。新增能力时优先扩展类型、默认值或可选策略,并保持既有方法的含义不变;需要废弃的字段则在兼容期内转换为新结构。这样,版本升级不会要求每个接入页面同步重写判断逻辑,问题排查也可以从公开 API 的输入和返回值开始。
验收应同时覆盖三个层面:构建产物能够解析,主题动作能够得到预期结果,异常路径能够回到可继续的状态。三个层面分别防止依赖配置错误、业务状态偏移和失败后页面失控;它们合在一起,才构成组件可以跨项目复用的最低交付标准。
组件侧可以把调用结果收敛成一个小型状态对象,再由页面按状态处理显示与重试入口:
type ComponentResult = {
ok: boolean
message: string
retryable: boolean
}
function resultOf(ok: boolean, message: string): ComponentResult {
return { ok, message, retryable: !ok }
}
function consumeResult(result: ComponentResult): string {
if (result.ok) return result.message
return result.retryable ? '可调整后重试' : result.message
}
上面的状态对象不替代业务模型,它只负责让调用端在成功、可恢复失败和不可继续三种结果之间作出稳定选择。这样,系统服务、存储实现或主题计算的内部细节不会穿透到页面文本和按钮回调中。
还应为关键状态定义可观察的验收点。例如,正常路径要确认输入被正确接收、结果字段被完整写入、再次进入时不会出现相互矛盾的显示;异常路径要确认错误不会覆盖最近一次有效结果,用户能够明确知道是否可以重试。对于依赖外部服务的能力,组件只应保存经过归一化的结果,不把瞬时的系统错误文本直接作为长期状态。这样即使设备环境、网络条件或系统版本不同,调用方也始终面对同一种结构化结果。
文档中的示例需要覆盖最小接入、默认行为和一个恢复分支。最小接入帮助使用者确认导入与初始化顺序;默认行为说明缺失参数时得到什么;恢复分支则让使用者知道异常后应继续使用当前状态、重新发起动作,还是提示用户检查依赖。把这三个层次同时讲清楚,组件才能在后续版本中保持可理解、可维护和可替换。
参考资料
HarmonyOS 组件工程需要把接口、依赖和运行边界同时写清。相关平台能力可参阅 HarmonyOS 开发者文档。
网硕互联帮助中心





评论前必须登录!
注册