足球口袋教练 HarmonyOS 设计(21):训练大页面拆分的模块边界规划
一、先把这篇文章的定位说清楚本文是一份尚待落地的模块化设计方案讨论对象是足球口袋教练中的训练大页面。文中的接口、类型与伪代码用于约束后续实现不代表这些拆分已经进入当前版本。这样定位的原因很直接当训练入口、动作详情、计时、计划和记录都由一个页面同时管理时任何一次小改动都会碰到共享状态、生命周期和持久化问题但在真实拆分完成、构建通过并获得运行证据之前不能把目标架构描述成既成事实。规划要解决的是“边界如何定”而不是简单追求文件数量。拆成五个页面文件却继续共享十几个可变字段仍然只是把复杂度搬家。真正有效的拆分需要回答四个问题领域模型由谁定义计时与记录由谁保存跨页面状态由谁持有页面退出后哪些任务必须继续。HarmonyOS 的状态管理与 MVVM 思路可以参阅华为开发者文档。本文只引用这一份平台资料重点放在训练业务自己的契约上。二、先冻结范围再讨论目录本轮规划包含训练目录、动作详情、训练计时、今日计划和训练记录五个视图。它们共享动作编号、训练时长和完成结果却有不同的生命周期。训练目录适合短生命周期查询计时任务可能跨越页面切换训练记录必须能够持久化统计视图只消费稳定结果不应直接控制计时器。暂不纳入本轮的内容包括云端账号同步、跨设备接续、语音播报和手表协同。这些能力都需要额外的平台配置与运行证据不能因为目录里预留了接口就宣称已经支持。当前规划只保证边界能够容纳未来适配不提前承诺具体能力。模块本轮职责明确不负责TrainingHome分类、筛选、进入动作详情计时器生命周期与记录写入TrainingDetail展示动作步骤并发起训练直接修改统计数据TrainingActive呈现计时状态与操作命令自行决定持久化格式TrainingPlan编排今日任务与完成顺序维护动作素材原始数据TrainingStats聚合已完成记录并展示趋势控制训练流程边界确定后目录只是边界的物理表达。页面依赖状态层状态层依赖服务接口服务层依赖模型与存储抽象反向依赖则通过命令和结果对象返回避免视图直接读写全局变量。三、领域模型先于页面组件第一步应当把训练动作、计划任务和训练记录定义成稳定模型。模型不引用 ArkUI 组件也不携带弹窗、颜色或路由对象。这样才能在单元测试、后台任务和不同设备页面中复用同一份业务语义。下面是设计阶段的类型草案。字段命名刻意区分“计划时长”“实际用时”和“完成时间”避免一个duration在不同页面表示不同含义。export type TrainingLevel beginner | intermediate | advanced export interface TrainingItem { id: string title: string categoryId: string level: TrainingLevel plannedSeconds: number stepIds: string[] enabled: boolean } export interface PlanTask { taskId: string trainingId: string order: number targetSets: number completedSets: number planDate: string } export interface TrainingRecord { recordId: string trainingId: string taskId?: string startedAt: number finishedAt: number elapsedSeconds: number completedSets: number finishReason: completed | cancelled | interrupted }模型还需要满足两个约束。其一持久化字段必须可序列化不把计时器句柄或 UI 上下文塞入记录其二业务标识不能用数组下标代替否则排序、筛选之后会把记录关联到错误动作。四、服务层以接口隔离变化训练数据的来源、计时方式和统计口径变化速度不同因此不适合放进一个万能服务。规划中拆成TrainingCatalogService、TrainingTimerService与TrainingReportService三组接口目录服务只负责查询计时服务维护会话报告服务保存记录并生成聚合结果。export interface TrainingCatalogService { list(categoryId?: string): PromiseTrainingItem[] getById(trainingId: string): PromiseTrainingItem | undefined } export interface TrainingTimerSnapshot { sessionId: string trainingId: string phase: idle | running | paused | finished startedAt?: number elapsedSeconds: number } export interface TrainingTimerService { start(trainingId: string): PromiseTrainingTimerSnapshot pause(sessionId: string): PromiseTrainingTimerSnapshot resume(sessionId: string): PromiseTrainingTimerSnapshot finish(sessionId: string): PromiseTrainingTimerSnapshot restore(): PromiseTrainingTimerSnapshot | undefined } export interface TrainingReportService { save(record: TrainingRecord): Promisevoid listByDate(from: string, to: string): PromiseTrainingRecord[] summarize(records: TrainingRecord[]): TrainingSummary }接口拆开以后本地静态训练目录可以先落地计时服务随后替换为可恢复实现统计页面也可以用固定记录验证聚合逻辑。任何一层尚未完成时都能通过明确的空结果或不可用状态降级而不是让页面猜测底层发生了什么。五、状态层只暴露视图真正需要的状态状态层的核心不是把所有字段集中到一个类而是把业务状态变成有限状态集合。规划中的TrainingViewModel负责把目录查询、计时快照和记录保存转换为页面可消费的状态同时提供唯一命令入口。export interface TrainingUiState { loading: boolean items: TrainingItem[] selected?: TrainingItem timer?: TrainingTimerSnapshot planTasks: PlanTask[] message?: string recoverable: boolean } export class TrainingViewModel { Trace state: TrainingUiState { loading: false, items: [], planTasks: [], recoverable: true } constructor( private catalog: TrainingCatalogService, private timer: TrainingTimerService, private report: TrainingReportService ) {} async load(categoryId?: string): Promisevoid { this.patch({ loading: true, message: undefined }) try { const items await this.catalog.list(categoryId) this.patch({ items, loading: false }) } catch (error) { this.patch({ loading: false, message: 训练内容暂时不可用 }) } } select(item: TrainingItem): void { this.patch({ selected: item, message: undefined }) } private patch(next: PartialTrainingUiState): void { this.state { ...this.state, ...next } } }页面不直接持有 Repository也不自行拼装错误文案。视图只观察loading、items、timer、message等稳定字段并通过load、select、start、pause、finish命令驱动变化。这样才能明确判断一次点击究竟触发了哪条业务路径。六、视图层的拆分与编排方式五个视图组件不应互相调用内部方法。顶层训练路由负责选择当前场景组件接收只读状态与回调。动作详情只发送“开始训练”意图活动训练页只发送计时命令完成后由状态层生成记录并决定去向。Component export struct TrainingScene { Param state: TrainingUiState Event onSelect: (item: TrainingItem) void Event onStart: (trainingId: string) void Event onPause: () void Event onFinish: () void build() { Column() { if (this.state.timer?.phase running) { TrainingActiveView({ snapshot: this.state.timer, onPause: this.onPause, onFinish: this.onFinish }) } else if (this.state.selected) { TrainingDetailView({ item: this.state.selected, onStart: this.onStart }) } else { TrainingHomeView({ items: this.state.items, loading: this.state.loading, onSelect: this.onSelect }) } } } }状态归属建议持有者离开页面后的处理筛选词、折叠项当前视图可以丢弃或按体验需要保存已选动作TrainingViewModel返回训练入口时可恢复计时会话TrainingTimerService页面离开后仍能查询快照今日计划PlanRepository重启后按日期恢复完成记录ReportRepository写入成功后才参与统计这套编排不会自动带来后台计时能力。后续若要支持切到后台仍准确计时应以开始时间和暂停区间计算时长并补充后台、锁屏、进程回收后的运行验证不能只依赖页面上的每秒回调。七、迁移顺序要让每一步都可回退拆分不适合一次性改完。建议先记录现有训练入口的可见行为再按“模型、纯服务、状态层、叶子视图、顶层编排”的顺序迁移。每一步都保留清晰的输入输出出现回归时可以定位到最近一层。1. 冻结动作列表、详情、开始、暂停、结束和记录查询的行为清单。 2. 提取领域类型并为旧数据增加显式转换函数。 3. 建立目录、计时、报告接口先用内存实现跑通契约测试。 4. 引入状态层让旧页面逐步改为消费统一状态。 5. 先拆无副作用的详情与统计视图再拆活动训练页。 6. 顶层页面最终只保留路由选择、组件装配和生命周期转发。 7. 替换正式持久化实现完成迁移、异常与恢复测试。迁移期间可以设置兼容适配器把旧页面已有数据转换成新模型。适配器是过渡边界不应长期承载新业务。等新旧行为对照通过后再删除旧字段和重复分支。八、失败、降级与验收证据设计方案只有覆盖失败路径才具备实施价值。目录读取失败时显示可重试空态素材缺失时仍展示文字步骤记录保存失败时保留待写入记录并提示用户路由恢复找不到动作时回到训练入口计时会话无法恢复时明确结束原会话不能静默生成一条完整记录。失败场景降级动作后续验收证据训练目录为空或解析失败空态加重试不渲染无效详情错误注入测试与页面截图计时中切到后台以时间戳重算不依赖 UI 回调次数前后台切换录屏与时长对照记录写入失败保留待写入对象统计不提前增加存储失败日志与重试结果路由参数失效返回训练入口并提示内容已变化无效参数自动化用例动作图片缺失使用占位图并保留文字步骤缺图构建包运行截图实施完成的验收条件也要事先约定页面文件不再保存计时器句柄计时服务能恢复运行、暂停和完成快照记录只有持久化成功后才进入统计五个视图能独立预览或测试拆分前后的核心操作行为一致构建通过并获得与能力标题直接对应的运行证据。在这些证据齐备前本文仍保持设计方案定位。后续实现文章应引用真实类型、构建结果和运行画面清楚区分“已完成”“正在迁移”和“待验证”。九、总结训练大页面拆分的关键不是把代码分散到更多文件而是建立单向、可验证的依赖模型定义业务语义服务封装变化状态层统一命令视图只负责呈现和交互。计时、计划与记录拥有不同生命周期必须分别确定状态归属和恢复策略。这份规划给出了后续开发可以逐项执行的边界、接口、迁移顺序、失败处理与验收条件。等模型、服务和组件真实落地并通过构建与运行验证后再把设计稿升级为实战复盘才能让标题、正文和工程事实始终一致。

相关新闻

为什么ChatBI是CEO押注的战略优先:三个价值层的组织重估

为什么ChatBI是CEO押注的战略优先:三个价值层的组织重估

导语 今天我想聊一个反直觉的结论:绝大多数企业都把ChatBI归为「AI技术在BI领域的工具升级」,仅此而已,但很少有CEO会将其定义为影响组织整体效率的战略级选择。这恰恰是当前很多企业数字化转型陷入瓶颈的核心原因。 我们都能感知到这个行业矛…

2026/7/23 15:31:18 阅读更多 →
校园二手交易平台设计与实现

校园二手交易平台设计与实现

摘 要 在高校校园内,学生们的学习与生活需求不断变化,校园二手交易平台的诞生恰逢其时。一方面,学生常面临学业更迭,像毕业、升学等,会产生大量闲置物品亟待处理。另一方面,大家消费观念日趋理性&#x…

2026/7/23 15:30:18 阅读更多 →
2026年GEO优化全解析:生成式引擎优化如何重构企业流量与品牌护城河

2026年GEO优化全解析:生成式引擎优化如何重构企业流量与品牌护城河

搜索范式转移,GEO成企业必选项用户行为正在从“Search(搜索)”向“Ask(提问)”迁移。据相关数据显示,超60%的用户开始习惯通过AI对话获取决策信息。在这一背景下,GEO(Generative Eng…

2026/7/23 15:30:18 阅读更多 →

最新新闻

如何优化AI生成的前端代码,避免同质化设计

如何优化AI生成的前端代码,避免同质化设计

1. 为什么AI生成的前端代码总带着"AI味"? 最近帮团队review了几个AI生成的前端项目,发现一个有趣现象:哪怕用不同AI工具(如Cursor、Claude Code Skill),产出的页面总带着相似的"AI味"。…

2026/7/23 15:40:21 阅读更多 →
多AI协作系统:智能任务分发与上下文共享的技术实现

多AI协作系统:智能任务分发与上下文共享的技术实现

最近在开发圈里,一个看似简单的需求却让不少团队头疼:如何让多个AI助手在同一项目中协同工作?传统的单AI对话模式已经无法满足复杂项目的需求,而简单的多窗口切换又让开发效率大打折扣。 这正是"-你不再是孤身一人了-"…

2026/7/23 15:40:21 阅读更多 →
原创角色动画生成与Meme化工具:环境部署与功能测试指南

原创角色动画生成与Meme化工具:环境部署与功能测试指南

这次我们来看一个关于 OC(原创角色)和水仙走路 meme 的项目,标题是“约的”。这个项目主要围绕原创角色的动画表现,特别是走路动作的 meme 化处理,适合对角色动画、meme 制作或本地化工具集成感兴趣的开发者。 从标题…

2026/7/23 15:40:21 阅读更多 →
AI记忆系统演进与上下文工程优化实践

AI记忆系统演进与上下文工程优化实践

1. AI记忆系统的演进背景2017年Transformer架构的提出彻底改变了自然语言处理的游戏规则。作为从业者,我亲眼见证了从GPT-3到ChatGPT的质变过程——当模型参数量突破千亿级别时,那些令人惊艳的"涌现能力"开始显现。但真正让我夜不能寐的&#…

2026/7/23 15:40:21 阅读更多 →
大模型实现代码注释自动化的工程实践

大模型实现代码注释自动化的工程实践

1. 项目概述:当大模型遇上代码注释自动化在软件开发领域,代码注释一直是个让人又爱又恨的存在。作为从业十余年的全栈工程师,我见过太多因为注释缺失或过时而引发的维护噩梦。最近尝试用大模型技术解决这个问题,效果出乎意料——单…

2026/7/23 15:40:21 阅读更多 →
拯救废片工具实测指南:从原理到场景的实用技巧

拯救废片工具实测指南:从原理到场景的实用技巧

1. 先搞清楚“拯救废片”到底能解决什么问题看到“拯救废片就像呼吸一样简单”这种标题,很多人的第一反应是“这工具是不是能一键修复所有拍坏的照片”。但实际测试下来,这类工具真正能稳定处理的,往往集中在几个特定场景:曝光不足…

2026/7/23 15:39:21 阅读更多 →

日新闻

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

更多请点击: https://intelliparadigm.com 第一章:从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表) 当AI副业主理人不再仅满足于单次服务交付,而是主动构建可复用、可裂变、可…

2026/7/23 0:00:25 阅读更多 →
AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

更多请点击: https://codechina.net 第一章:AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析 在对2,346篇跨行业AI生成文案的A/B测试数据进行聚类分析后,我们发现&#xff1…

2026/7/23 0:01:26 阅读更多 →
Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/23 0:01:26 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/22 8:58:19 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/22 19:43:43 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/22 12:54:44 阅读更多 →

月新闻