ArkTS 做 5 态数据流 —— 咖啡电量的代谢状态机怎么驱动 UI
掘金本周最热 · 软件开发
咖啡电量(CoffeeBattery)首页要展示用户当前的"代谢状态":是刚喝下的吸收期?已经到巅峰期?在稳定区?还是精神疲劳区?用户主动戒咖期?这是 5 种业务状态,UI 要据此显示不同颜色、不同文案、不同图标。做了几版之后,最清爽的做法是 一个纯函数判定状态 + 所有 UI 读同一个状态字段 。记录一下咖啡电量的 MetabolicState 这个 5 态机设计,顺便分享给有需要的朋友。 一、为什么是 5 态 朴素做法:按浓度(current mg)直接分段。咖啡电量能量满分 100 mg(理论峰值),所以: // 朴素 3 态 if (current > 70 ) return 'high' if (current > 30 ) return 'medium' return 'low' 但这个分法有两个问题。 第一个问题:吸收期的"假低" 。用户刚喝完一杯咖啡的头 10 分钟,吸收还没达峰,current 还在 50 mg 以下。按浓度判定会归类为 'medium'——但对用户的真实感是"刚喝下,等起效",和"稳定期 50 mg"完全不同。 第二个问题:戒咖的"假低" 。用户主动戒咖期间, current 当然很低(因为没摄入),归类为 'low'。但 UI 应该显示"戒咖进行中"而不是"低能量"——两种状态语义不同。 于是 浓度分段不够 ,要引入 行为语义维度 。咖啡电量定义了 5 态: // model/MetabolicState.ets export type StateType = 'absorbing' | 'peak' | 'stable' | 'fatigue' | 'detox' absorbing :刚摄入,吸收期(0-30 分钟) peak :浓度 > 150mg,巅峰运转 stable :浓度 30-150mg,稳定区 fatigue :浓度 < 30mg,疲劳区 detox :用户开启了戒咖模式 5 态是 信息密度和认知复杂度的平衡点 : 3 态(high/medium/low)信息不够 7+ 态用户认不过来(看一眼不知道该怎么做) 5 态刚好对应咖啡摄入的典型行为日历:喝(absorbing)→ 兴奋(peak)→ 稳(stable)→ 累(fatigue)→ 休息(detox) 二、吸收期用时间判定,其他用浓度判定 5 态的判定条件混合了"时间"和"浓度"两个维度: // model/MetabolicState.ets export class MetabolicState { static getStatus ( records : IntakeRecord [], now : number , isDetox : boolean ): MetabolicStatus { // 1. detox 优先 if (isDetox) { return { state : 'detox' , remainingMin : 0 } } // 2. absorbing:最新摄入 30 分钟内(时间判定) if (records. length > 0 ) { const latest = records[ 0 ] // 已按 timestamp DESC const elapsedMin = (now - latest. timestamp ) / 60000 if (elapsedMin < Constants . ABSORPTION_MINUTES ) { return { state : 'absorbing' , remainingMin : Math . ceil ( Constants . ABSORPTION_MINUTES - elapsedMin), drinkName : latest. drinkName , } } } // 3. 浓度判定 const level = CaffeineEngine . calculateLevel (records, now) if (level > Constants . PEAK_THRESHOLD ) { // 150 return { state : 'peak' , level } } if (level > Constants . SLEEP_SAFE_MG ) { // 30 return { state : 'stable' , level } } return { state : 'fatigue' , level } } } 判定顺序有讲究 : detox 第一 :用户主动戒咖期间,任何浓度判定都要让位 absorbing 第二 :吸收期的"用户体验感"覆盖浓度数字——即使吸收期浓度已经攀到 100mg,用户内心感觉是"