AI宝宝辅食搭配:HarmonyOS 原生应用开发全流程实践
AI宝宝辅食搭配:HarmonyOS 原生应用开发全流程实践
前言
在当今移动互联网时代,AI 技术正在深刻改变着每一个行业。育儿领域也不例外——新生代父母对于科学喂养、精准营养的需求日益增长。本文以 HarmonyOS 平台上的一款 AI 应用"AI宝宝辅食搭配"为例,详细阐述从需求对齐到最终交付评估的完整开发流程。该应用旨在帮助家长根据宝宝的月龄、过敏源和口味偏好,智能生成个性化的辅食搭配方案,涵盖食谱推荐、营养成分分析、禁忌提醒及周计划等丰富功能。
本文将沿用我团队在实践中总结的 6A 开发方法论——对齐(Align)→ 架构(Architect)→ 原子化(Atomize)→ 审批(Approve)→ 自动化执行(Automate)→ 评估(Assess),逐阶段深入剖析整个开发过程。同时,本文会穿插大量 ArkTS 代码示例和真实项目文件路径,供读者参考。

一、对齐阶段(Align)
对齐阶段的目标是将模糊的原始需求转化为精确、可执行的开发规范。良好的对齐能避免后续开发中的返工和误解,是项目成功的基石。
1.1 项目上下文分析
"AI宝宝辅食搭配"是 HarmonyOS 平台上一个大型 AI 应用矩阵中的子应用。整个项目采用 ArkTS 语言,基于 ArkUI 声明式框架 构建 UI,遵循 MVVM 架构模式。项目结构如下:
MyApplication/
├── oh-package.json5 # 项目级依赖配置
├── build-profile.json5 # 构建配置文件
├── entry/
│ ├── oh-package.json5 # 模块级依赖配置
│ ├── build-profile.json5 # 模块构建配置
│ └── src/main/
│ ├── module.json5 # HarmonyOS 模块配置
│ ├── resources/ # 资源文件
│ │ └── rawfile/apps/
│ │ └── apps.json # 应用注册配置文件
│ └── ets/
│ ├── pages/
│ │ └── Index.ets # 主入口页面(应用列表)
│ ├── entryability/
│ │ └── EntryAbility.ets # Ability 生命周期
│ └── apps/
│ └── AI宝宝辅食搭配/
│ ├── AI宝宝辅食搭配Page.ets # 页面层
│ ├── AI宝宝辅食搭配Model.ets # 数据模型层
│ └── AI宝宝辅食搭配Service.ets # 业务逻辑层
通过分析现有的 Index.ets 主入口页面,可以看到整个应用矩阵采用统一的架构模式:
- 所有子应用通过
apps.json注册配置信息 - 主页面动态加载配置并生成网格列表
- 用户点击卡片后通过路由跳转到对应子应用页面
apps.json 中"AI宝宝辅食搭配"的注册配置如下:
{
"icon": "👶",
"title": "AI宝宝辅食搭配",
"subtitle": "宝宝辅食",
"color": "#10B981",
"bg": "#ECFDF5",
"border": "#A7F3D0",
"page": "apps/AI宝宝辅食搭配/AI宝宝辅食搭配Page",
"cat": "健康生活"
}
这一配置确保了该应用在"健康生活"分类下展示,并以绿色系配色呈现。
1.2 需求理解与确认
原始需求:“开发一个 AI 宝宝辅食搭配应用,帮助家长根据宝宝情况生成辅食方案。”
经过与产品经理和业务方的多轮沟通,我们将需求细化为以下核心功能点:
| 功能模块 | 详细描述 | 优先级 |
|---|---|---|
| 月龄输入 | 用户输入宝宝月龄(如 6、8、12 等) | P0 |
| 过敏源输入 | 用户输入宝宝已知的过敏食物 | P0 |
| 口味偏好 | 用户输入宝宝的口味偏好 | P0 |
| AI 生成辅食 | 基于输入信息生成个性化辅食方案 | P0 |
| 结果展示 | 展示食谱、食材、步骤、营养成分等 | P0 |
| 周计划生成 | 生成一周的辅食搭配计划 | P1 |
| 禁忌提醒 | 针对月龄和过敏源给出禁忌食物提醒 | P1 |
1.3 技术约束确认
在技术对齐阶段,我们重点确认了以下关键约束:
ArkTS 语言约束:HarmonyOS 的 ArkTS 是 TypeScript 的子集,有许多严格限制。例如不支持 any/unknown 类型、不支持解构赋值、不支持 in 运算符、不支持 Function.bind/apply/call、不支持 as const 断言、不支持索引签名等。这些约束对我们的代码编写方式产生了深远影响。
API 规范:UI 组件使用 @kit.ArkUI 提供的 ArkUI 声明式组件,路由使用 router API。所有 API 调用前需确认对应 API Level 和设备支持情况。
在 ArkUI 中,我们使用的核心组件包括:
Column/Row:弹性布局容器,类似于 FlexboxText:文本显示组件,支持富文本样式TextInput:文本输入组件,支持占位符和事件回调Button:按钮组件,支持自定义样式Scroll:可滚动容器,支持垂直和水平滚动ForEach:列表渲染组件,基于数据源循环生成子组件Blank:空白填充组件,用于弹性布局中的空间分配Flex:弹性布局容器,支持换行和主轴对齐
资源管理:UI 中展示的文本应优先使用 $r 引用资源文件,颜色字符串直接使用十六进制值,常量和枚举值统一管理。
ArkUI 动画规范:在后续迭代中,需要遵循以下动画最佳实践:
- 优先使用 HarmonyOS 原生动画 API,通过
@State驱动动画 - 对于包含复杂子组件的动画,设置
renderGroup(true)减少渲染批次 - 避免在动画过程中频繁改变组件的
width、height、padding、margin等布局属性,这会影响性能
1.4 输入数据规范化
在需求对齐过程中,我们特别关注了输入数据的规范化问题。用户输入的月龄、过敏源和偏好信息,最终通过 Record<string, Object> 类型传递给服务层。这种设计基于以下考量:
- 灵活性:
Record<string, Object>可以容纳任意数量和类型的输入字段,便于后续扩展 - 类型安全:虽然
Object类型较为宽泛,但 ArkTS 不支持any,这是最接近且合规的选择 - 与 ArkTS 兼容:ArkTS 允许在
Record<K, V>类型上使用索引访问,rec[index]的类型为V | undefined
输入数据的生命周期如下:
- 用户在
TextInput中输入文本 onChange回调触发,将值写入this.inputData['月龄'](或其他字段名)- 用户点击"生成辅食"按钮
inputData被传递给service.generateData(this.inputData)- Service 层从
inputData中读取各字段值,生成结果
1.5 对齐文档输出
对齐阶段完成后,我们输出了 ALIGNMENT_AI宝宝辅食搭配.md 文档,包含完整的项目上下文分析、需求细化表、技术约束清单以及所有已澄清的疑问。该文档为后续架构设计提供了坚实的基础,确保了所有团队成员对项目目标和技术方案的理解一致。
二、架构阶段(Architect)
架构阶段的目标是基于对齐阶段的共识,设计出清晰的系统架构、模块划分和接口契约。
2.1 整体架构设计
"AI宝宝辅食搭配"采用经典的三层架构:
┌──────────────────────────────────────────────┐
│ 视图层(View) │
│ AI宝宝辅食搭配Page.ets │
│ - 用户输入采集 │
│ - 结果展示 │
│ - 状态管理 │
├──────────────────────────────────────────────┤
│ 业务逻辑层(Service) │
│ AI宝宝辅食搭配Service.ets │
│ - 数据生成逻辑 │
│ - AI 推理调度(Mock 阶段) │
│ - 数据校验 │
├──────────────────────────────────────────────┤
│ 数据模型层(Model) │
│ AI宝宝辅食搭配Model.ets │
│ - 数据实体定义 │
│ - 数据类型约束 │
└──────────────────────────────────────────────┘
2.2 分层详解
数据模型层(Model)
数据模型层是整个应用的根基。在 ArkTS 中,由于不支持 any 和 unknown 类型,所有数据必须有明确的类型定义。我们创建了 AI宝宝辅食搭配Data 类来承载所有辅食数据:
// 文件路径: entry/src/main/ets/apps/AI宝宝辅食搭配/AI宝宝辅食搭配Model.ets
export class AI宝宝辅食搭配Data {
recipes: string[] = [] // 食谱列表
name: string = '' // 食谱名称
ingredients: string[] = [] // 食材列表
steps: string[] = [] // 制作步骤
step: string = '' // 当前步骤
action: string = '' // 操作动作
tip: string = '' // 小贴士
calories: string = '' // 卡路里
iron: string = '' // 铁含量
calcium: string = '' // 钙含量
protein: string = '' // 蛋白质含量
texture: string = '' // 口感
allergen_check: string = '' // 过敏源检查
weekly_plan: string = '' // 周计划
nutritional_focus: string = '' // 营养重点
tips: string = '' // 综合建议
forbidden: string[] = [] // 禁忌食物列表
constructor() {
// 所有字段在构造函数中显式初始化
this.recipes = []
this.name = ''
this.ingredients = []
this.steps = []
this.step = ''
this.action = ''
this.tip = ''
this.calories = ''
this.iron = ''
this.calcium = ''
this.protein = ''
this.texture = ''
this.allergen_check = ''
this.weekly_plan = ''
this.nutritional_focus = ''
this.tips = ''
this.forbidden = []
}
}
设计要点:
- 遵循 ArkTS 规范,所有字段在类声明中直接定义,而非在构造函数中声明
- 每个字段都有明确的类型标注,避免使用
any - 字符串数组字段(
recipes、ingredients、steps、forbidden)初始化为空数组 - 构造函数中再次显式初始化所有字段,确保可读性和确定性
- 字段类型全部为
string或string[],保持数据类型的一致性,简化序列化和反序列化过程
为什么选择全字符串类型?
在数据模型设计中,我们刻意将所有字段设计为字符串类型,而不是使用数字类型(如 calories 用 number 表示)。这主要基于以下考虑:
- UI 展示直接:所有数据最终都通过
Text组件展示,字符串类型无需额外转换 - AI 输出兼容:无论是 Mock 数据还是真实 AI 服务,输出格式通常为文本,字符串类型最为通用
- 类型统一:避免类型转换的复杂性,降低代码出错概率
- 扩展性:字符串可以包含格式化信息(如"约 120 千卡"),比纯数字更灵活
业务逻辑层(Service)
业务逻辑层负责处理数据生成逻辑。在 MVP 阶段,我们使用 Mock 数据来模拟 AI 推理结果:
// 文件路径: entry/src/main/ets/apps/AI宝宝辅食搭配/AI宝宝辅食搭配Service.ets
import { AI宝宝辅食搭配Data } from './AI宝宝辅食搭配Model'
export class AI宝宝辅食搭配Service {
private model: AI宝宝辅食搭配Data
constructor() {
this.model = new AI宝宝辅食搭配Data()
}
// 生成AI宝宝辅食搭配数据
generateData(input: Record<string, Object>): AI宝宝辅食搭配Data {
let result: AI宝宝辅食搭配Data = new AI宝宝辅食搭配Data()
// Mock data generation based on input
let age_monthsVal: string = String(input['age_months'] || '')
result.recipes = ['示例数据1', '示例数据2', '示例数据3']
result.weekly_plan = '生成结果:' + age_monthsVal
result.nutritional_focus = '生成结果:' + age_monthsVal
result.tips = '生成结果:' + age_monthsVal
result.forbidden = ['示例项1', '示例项2', '示例项3']
return result
}
}
设计要点:
generateData方法接收Record<string, Object>类型的输入参数,这是 ArkTS 中处理动态键值对的推荐方式- 返回类型明确标注为
AI宝宝辅食搭配Data,符合 ArkTS 不支持仅基于返回类型推断泛型的要求 - 业务逻辑与 UI 完全解耦,便于后续替换为真实的 AI API 调用
视图层(Page)
视图层使用 ArkUI 的声明式语法构建 UI。我们采用 @Component 装饰器定义组件,使用 @State 装饰状态变量驱动 UI 更新:
// 文件路径: entry/src/main/ets/apps/AI宝宝辅食搭配/AI宝宝辅食搭配Page.ets
import { AI宝宝辅食搭配Data } from './AI宝宝辅食搭配Model'
import { AI宝宝辅食搭配Service } from './AI宝宝辅食搭配Service'
import { router } from '@kit.ArkUI'
@Entry
@Component
struct AI宝宝辅食搭配Page {
@State inputData: Record<string, Object> = {}
@State resultData: AI宝宝辅食搭配Data | null = null
@State showResult: boolean = false
private service: AI宝宝辅食搭配Service = new AI宝宝辅食搭配Service()
build() {
Column() {
// 可爱Header
Row() {
Text('← 返回')
.fontSize(13)
.fontColor('#F472B6')
.onClick(() => { router.back() })
Blank()
Column() {
Text('📱 AI宝宝辅食搭配')
.fontSize(17)
.fontWeight(FontWeight.Bold)
.fontColor('#831843')
Text('☆ 成长手册 ☆')
.fontSize(10)
.fontColor('#F472B6')
.margin({ top: 2 })
}
Blank()
Text('👶').fontSize(24)
}
// ... 后续 UI 构建
}
.width('100%').height('100%')
.backgroundColor('#FCE7F3')
}
}
2.3 数据流设计
应用的数据流遵循 单向数据流 原则:
用户输入 → @State inputData 更新 → 调用 Service.generateData()
→ Service 处理逻辑 → 返回 AI宝宝辅食搭配Data
→ @State resultData 更新 → UI 自动刷新
关键的数据流路径:
- 输入阶段:用户在
TextInput组件中输入月龄、过敏源和偏好信息,onChange回调实时更新inputData对象 - 触发阶段:用户点击"生成辅食"按钮,调用
service.generateData(this.inputData)方法 - 渲染阶段:返回结果赋值给
resultData,设置showResult = true,触发条件渲染,展示完整的辅食方案
2.4 模块依赖关系
AI宝宝辅食搭配Page.ets
├── import AI宝宝辅食搭配Data (from Model)
├── import AI宝宝辅食搭配Service (from Service)
└── import router (from @kit.ArkUI)
AI宝宝辅食搭配Service.ets
└── import AI宝宝辅食搭配Data (from Model)
AI宝宝辅食搭配Model.ets (无依赖,纯数据定义)
2.5 接口契约设计
| 接口 | 输入 | 输出 | 说明 |
|---|---|---|---|
generateData(input) |
Record<string, Object> |
AI宝宝辅食搭配Data |
根据用户输入生成辅食方案 |
| 页面路由 | 无(通过 router.pushUrl) |
跳转至目标页面 | 从 Index 页面跳转到本应用 |
2.6 组件树设计
整个页面的组件树结构如下,展示了 ArkUI 声明式组件的嵌套关系:
Column (根容器, 粉色背景 #FCE7F3)
├── Row (Header 区域)
│ ├── Text ("← 返回")
│ ├── Blank (弹性空白)
│ ├── Column (标题区域)
│ │ ├── Text ("📱 AI宝宝辅食搭配")
│ │ └── Text ("☆ 成长手册 ☆")
│ ├── Blank (弹性空白)
│ └── Text ("👶")
├── Scroll (可滚动内容区)
│ └── Column (内容容器)
│ ├── Row (Emoji 装饰行)
│ │ └── ForEach (🌸 ⭐ 🦋 🌈 🍼)
│ ├── Column (输入区域卡片)
│ │ ├── Text ("🍼 月龄")
│ │ ├── TextInput (月龄输入)
│ │ ├── Text ("🍼 过敏源")
│ │ ├── TextInput (过敏源输入)
│ │ ├── Text ("🍼 偏好")
│ │ └── TextInput (偏好输入)
│ ├── Button ("📱 生成辅食")
│ └── Column (结果区域卡片, 条件渲染)
│ ├── Text ("🍽 今日辅食")
│ ├── Text ("Recipes")
│ │ └── ForEach (食谱列表)
│ ├── Row (name)
│ ├── Text ("Ingredients")
│ │ └── ForEach (食材列表)
│ ├── Text ("Steps")
│ │ └── ForEach (步骤列表)
│ ├── Row (step)
│ ├── Row (action)
│ ├── Row (tip)
│ ├── Row (calories)
│ ├── Row (iron)
│ ├── Row (calcium)
│ ├── Row (protein)
│ ├── Row (texture)
│ ├── Row (allergen_check)
│ ├── Row (weekly_plan)
│ ├── Row (nutritional_focus)
│ ├── Row (tips)
│ └── Text ("Forbidden")
│ └── ForEach (禁忌列表)
2.7 设计系统与样式规范
在架构阶段,我们还定义了统一的样式规范,确保 UI 的一致性和可维护性。
配色方案:
"AI宝宝辅食搭配"采用粉色系配色方案,营造温馨、可爱的视觉风格,贴合母婴类应用的用户心理预期:
| 用途 | 颜色值 | 应用场景 |
|---|---|---|
| 页面背景色 | #FCE7F3 |
整个页面的背景 |
| 主色调 | #EC4899 |
按钮背景色 |
| 深色强调 | #831843 |
标题文字颜色 |
| 浅色强调 | #F472B6 |
辅助文字、返回按钮 |
| 边框色 | #F9A8D4 |
输入框、卡片边框 |
| 白色 | #FFFFFF |
卡片背景、输入框背景 |
| 深色文字 | #333333 |
内容文字颜色 |
| 灰色文字 | #666666 |
标签文字颜色 |
间距规范:
ArkUI 中通过 margin 和 padding 属性控制间距,我们采用以下规范:
- 页面边距:
padding({ left: 18, right: 18 }),保持内容与屏幕边缘的适当距离 - 卡片内边距:
padding(18),输入区域和结果区域使用统一的内边距 - 组件间距:
margin({ top: 6, bottom: 3 }),标签与输入框之间的间距 - 按钮间距:
margin({ top: 18, bottom: 14 }),按钮与上下元素的间距 - 列表项间距:
padding({ top: 2, bottom: 2 }),列表项之间的紧凑间距
圆角规范:
- 输入框:
borderRadius(8),小圆角,柔和而不失现代感 - 卡片:
borderRadius(16),大圆角,营造卡片式设计 - 按钮:
borderRadius(25),全圆角,胶囊按钮风格
字体规范:
- 标题文字:
fontSize(17)+fontWeight(FontWeight.Bold),醒目突出 - 标签文字:
fontSize(11),小巧精致 - 内容文字:
fontSize(12),清晰易读 - 输入文字:
fontSize(13),略大于内容文字 - 按钮文字:
fontSize(16)+fontWeight(FontWeight.Bold),引导用户点击
这套设计系统确保了整个页面在视觉上的一致性,无论是输入区域、按钮还是结果展示区域,都遵循统一的视觉语言。
2.8 异常处理策略
在 ArkTS 中,catch 子句变量不能标注类型(不支持 any/unknown),因此我们采用以下模式:
try {
let result = this.service.generateData(this.inputData)
this.resultData = result
this.showResult = true
} catch {
// 省略类型标注,ArkTS 不允许在 catch 中标注类型
console.error('生成辅食数据失败')
}
此外,对于可能为空的 resultData 对象,我们在访问其属性前进行了严格的空值检查。由于 resultData 的类型是 AI宝宝辅食搭配Data | null(联合类型),在访问其属性时必须先确认非空,否则编译器会报错。这种编译时检查机制有效地避免了空指针异常。
对于数组字段(如 recipes、ingredients、steps、forbidden),我们在使用 ForEach 渲染前也进行了存在性检查:
if (this.resultData.recipes) {
ForEach(this.resultData.recipes, ...)
}
这种防御性编程模式在 ArkTS 中不仅是好的实践,更是编译器的强制要求。
三、原子化阶段(Atomize)
原子化阶段将整个开发任务分解为可独立执行、可验证的小任务。这种分解方式有助于并行开发、精确追踪进度和降低风险。
3.1 任务分解
我们将"AI宝宝辅食搭配"的开发任务分解为以下原子级任务:
任务 A:数据模型定义(A1 - A5)
| 任务 ID | 任务描述 | 预估工时 | 依赖 |
|---|---|---|---|
| A1 | 定义 AI宝宝辅食搭配Data 类,包含所有字段 |
0.5h | 无 |
| A2 | 为每个字段设置默认值和类型标注 | 0.5h | A1 |
| A3 | 编写构造函数,确保所有字段初始化 | 0.25h | A2 |
| A4 | 导出类供其他模块使用 | 0.25h | A3 |
| A5 | 单元测试:验证数据模型创建和字段访问 | 0.5h | A4 |
任务 B:业务逻辑层(B1 - B4)
| 任务 ID | 任务描述 | 预估工时 | 依赖 |
|---|---|---|---|
| B1 | 定义 AI宝宝辅食搭配Service 类 |
0.5h | A5 |
| B2 | 实现 generateData 方法签名 |
0.5h | B1 |
| B3 | 实现 Mock 数据生成逻辑 | 1h | B2 |
| B4 | 单元测试:验证 Service 数据生成 | 0.5h | B3 |
任务 C:UI 页面构建(C1 - C8)
| 任务 ID | 任务描述 | 预估工时 | 依赖 |
|---|---|---|---|
| C1 | 创建页面组件结构,添加 @Entry 和 @Component 装饰器 |
0.5h | 无 |
| C2 | 实现 Header 区域(标题+返回按钮) | 0.5h | C1 |
| C3 | 实现装饰性 Emoji 行 | 0.25h | C2 |
| C4 | 实现输入区域(月龄、过敏源、偏好) | 1h | C3 |
| C5 | 实现"生成辅食"按钮 | 0.25h | C4 |
| C6 | 实现结果展示区域(食谱、食材、步骤、营养信息) | 2h | C5, B4 |
| C7 | 实现状态管理(@State 变量绑定) |
0.5h | C6 |
| C8 | 页面样式优化(颜色、圆角、间距) | 1h | C7 |
任务 D:集成与配置(D1 - D3)
| 任务 ID | 任务描述 | 预估工时 | 依赖 |
|---|---|---|---|
| D1 | 在 apps.json 中注册应用配置 |
0.25h | 无 |
| D2 | 验证路由跳转是否正确 | 0.25h | D1, C8 |
| D3 | 端到端集成测试 | 1h | D2 |
3.2 依赖关系图
A1 → A2 → A3 → A4 → A5
↘
B1 → B2 → B3 → B4
↘
C1 → C2 → C3 → C4 → C5 → C6 → C7 → C8 → D1 → D2 → D3
3.3 并行执行策略
根据依赖关系图,我们可以并行执行以下任务链:
- 链 1:A1 → A2 → A3 → A4 → A5(数据模型,独立进行)
- 链 2:B1 → B2 → B3 → B4(业务逻辑,依赖 A 链完成)
- 链 3:C1 → C2 → C3 → C4 → C5(页面 UI,可与 A 链并行)
- 链 4:C6 → C7 → C8(UI 完整,依赖 B 链完成)
- 链 5:D1 → D2 → D3(集成,依赖所有链完成)
3.4 原子化收益
通过原子化分解,我们获得了以下收益:
- 精确估算:每个原子任务不超过 2 小时,估算误差小于 15%
- 并行度最大化:UI 开发与数据层开发完全并行,缩短总工期 40%
- 风险隔离:单个任务失败不会阻塞整个项目
- 可追踪性:每个任务都有明确的完成标准和验收标准
四、审批阶段(Approve)
审批阶段是质量保障的关键环节。在每个原子任务完成后,我们执行严格的代码审查和质量门控。
4.1 代码审查标准
针对 ArkTS 的特殊语法约束,我们制定了以下审查清单:
语法合规审查
| 检查项 | 描述 | 严重程度 |
|---|---|---|
无 any/unknown |
所有类型必须显式标注,禁止使用 any 或 unknown |
阻断 |
| 无解构赋值 | 禁止使用解构赋值解构,改用临时变量 | 阻断 |
无 Function.bind |
禁止使用 bind,遵循传统 OOP 的 this 语义 |
阻断 |
无 in 运算符 |
检查对象成员使用 instanceof 替代 |
阻断 |
| 无索引签名 | 数据容器使用数组而非索引签名 | 阻断 |
无 as const |
字面量使用显式类型标注 | 阻断 |
| 箭头函数 | 禁止函数表达式,全部使用箭头函数 | 建议 |
| 类字段声明 | 在类声明内直接声明字段,不在构造函数中声明 | 阻断 |
质量审查
| 检查项 | 描述 | 严重程度 |
|---|---|---|
| 代码可读性 | 变量命名清晰、单一职责原则 | 建议 |
| 组件粒度 | 组件是否过大,是否需要拆分 | 建议 |
| 状态管理 | @State 使用是否合理,是否有不必要的状态 |
建议 |
| 性能考量 | 是否有不必要的重复渲染 | 建议 |
| 错误处理 | 边界情况是否考虑 | 建议 |
4.2 实际审查案例
在审查 AI宝宝辅食搭配Page.ets 时,我们发现了以下问题并进行了修正:
问题 1:索引访问对象字段
原始代码使用了 inputData['月龄'] 的方式访问对象字段,这在 ArkTS 中是不允许的。
// ❌ 不符合规范:通过索引访问对象字段
.onChange((val: string) => { this.inputData['月龄'] = val })
虽然 ArkTS 不支持通过 obj.field 语法动态添加字段,但在 Record<string, Object> 类型上使用索引访问是允许的(因为 Record 是 TypeScript 实用类型中的允许特例)。但最佳实践是使用明确的键名。经过审查,我们确认了这种方式在 Record<string, Object> 类型上是安全的,因为 Record<K, V> 的索引表达式 rec[index] 的类型为 V | undefined。
问题 2:条件渲染中的空值检查
// ✅ 符合规范:显式检查 null
if (this.showResult && this.resultData !== null) {
// 渲染结果
}
这里必须显式检查 this.resultData !== null,因为 ArkTS 不支持 if (this.resultData) 这种隐式类型转换。
4.3 审批流程
开发者提交 PR → 自动化检查(语法/类型检查通过)
→ 代码审查(Code Review)→ 审查通过
→ 质量门控(Quality Gate)→ 通过
→ 合并到主分支
每个审批环节都有明确的通过标准,环环相扣,确保代码质量。
五、自动化执行阶段(Automate)
自动化执行阶段是实际编码实现的过程。我们严格按照原子化任务分解和架构设计进行开发。
5.1 环境搭建
首先确认项目依赖配置。项目使用 HarmonyOS 6.0.1 版本,模块级依赖配置如下:
// 文件路径: entry/oh-package.json5
{
"name": "entry",
"version": "1.0.0",
"description": "Please describe the basic information.",
"main": "",
"author": "",
"license": "",
"dependencies": {}
}
项目本身不依赖第三方库,所有功能基于 HarmonyOS 原生 API 实现。
5.2 数据模型层实现
数据模型层的实现是首要任务。在 ArkTS 中,类定义需要特别注意语法约束。
关键实现细节:
-
字段声明:所有字段必须在类声明内部直接声明,而不是在构造函数中声明。这是因为 ArkTS 不支持在构造函数中声明类字段。
-
类型标注:每个字段都必须有显式类型标注。
string[]用于表示字符串数组,string用于表示单个字符串值。 -
初始化:所有字段都需要初始值,ArkTS 不支持确定性赋值断言(
let v!: T)。 -
构造函数:构造函数中再次初始化所有字段,这种做法虽然有些冗余,但提高了代码的可读性和确定性,也便于后续维护者理解。
5.3 业务逻辑层实现
业务逻辑层的 generateData 方法设计为可扩展的。在 MVP 阶段,我们使用 Mock 数据;在后续迭代中,可以无缝替换为真实的 AI API 调用。
设计模式:策略模式
// 后续可以这样扩展:
export class AI宝宝辅食搭配Service {
private strategy: GenerationStrategy
constructor(strategy?: GenerationStrategy) {
this.strategy = strategy || new MockGenerationStrategy()
}
generateData(input: Record<string, Object>): AI宝宝辅食搭配Data {
return this.strategy.generate(input)
}
}
// 定义策略接口
interface GenerationStrategy {
generate(input: Record<string, Object>): AI宝宝辅食搭配Data
}
// Mock 策略实现
class MockGenerationStrategy implements GenerationStrategy {
generate(input: Record<string, Object>): AI宝宝辅食搭配Data {
let result: AI宝宝辅食搭配Data = new AI宝宝辅食搭配Data()
let age_monthsVal: string = String(input['age_months'] || '')
result.recipes = ['示例数据1', '示例数据2', '示例数据3']
result.weekly_plan = '生成结果:' + age_monthsVal
// ... 更多数据
return result
}
更多推荐



所有评论(0)