第6次:数据模型设计与实现
数据模型是应用的骨架,定义了数据的结构和类型。本次课程将深入设计 React 学习教程 App 的完整数据模型,为后续功能开发奠定基础。
学习目标
- 理解数据模型设计原则
- 掌握学习模块数据结构设计
- 设计课程内容数据结构
- 实现用户进度数据模型
- 完成测验相关数据模型
- 编写完整的 Models.ets 文件
效果

6.1 数据模型设计原则
设计原则
- 单一职责:每个接口只描述一种数据
- 类型安全:使用明确的类型,避免 any
- 可扩展性:预留扩展空间
- 一致性:命名和结构保持一致
- 文档化:添加清晰的注释
命名规范
typescript
// 接口:名词,PascalCase
interface LearningModule { }
interface UserProgress { }
// 类型别名:描述性名称
type DifficultyType = 'beginner' | 'basic' | 'intermediate';
type CodeLanguage = 'javascript' | 'typescript';
// 常量:UPPER_SNAKE_CASE
const DEFAULT_USER_PROGRESS: UserProgress = { };
6.2 学习模块数据结构
模块层级关系
App
└── LearningModule (学习模块)
└── Lesson (课程)
└── LessonContent (课程内容)
├── ContentSection (内容段落)
├── CodeExample (代码示例)
└── TOCItem (目录项)
LearningModule 接口
typescript
/**
* 学习模块
* 代表一个完整的学习单元,如"React 简介"、"Hooks 基础"
*/
export interface LearningModule {
/** 模块唯一标识 */
id: string;
/** 模块标题 */
title: string;
/** 模块描述 */
description: string;
/** 难度等级 */
difficulty: DifficultyType;
/** 图标(emoji 或图片路径) */
icon: string;
/** 主题色 */
color: string;
/** 课程数量 */
lessonCount: number;
/** 预计学习时间 */
estimatedTime: string;
/** 前置模块 ID 列表 */
prerequisites: string[];
/** 课程列表 */
lessons: Lesson[];
}
Lesson 接口 课程接口
typescript
/**
* 课程
* 模块下的具体课程单元
*/
export interface Lesson {
/** 课程唯一标识 */
id: string;
/** 所属模块 ID */
moduleId: string;
/** 课程标题 */
title: string;
/** 课程描述 */
description: string;
/** 排序序号 */
order: number;
/** 课程内容 */
content: LessonContent;
/** 是否有代码练习 */
hasPlayground: boolean;
/** 是否有测验 */
hasQuiz: boolean;
}
难度类型定义
typescript
/**
* 难度等级类型
*/
export type DifficultyType =
| 'beginner' // 入门
| 'basic' // 基础
| 'intermediate' // 进阶
| 'advanced' // 高级
| 'ecosystem'; // 生态
6.3 课程内容数据结构
LessonContent 接口
typescript
/**
* 课程内容
* 包含课程的所有内容元素
*/
export interface LessonContent {
/** 内容段落列表 */
sections: ContentSection[];
/** 代码示例列表 */
codeExamples: CodeExample[];
/** 目录 */
tableOfContents: TOCItem[];
/** 关键要点 */
keyTakeaways: string[];
}
ContentSection 接口
typescript
/**
* 内容段落类型
*/
export type SectionType =
| 'text' // 普通文本
| 'code' // 代码块
| 'tip' // 提示
| 'warning' // 警告
| 'note'; // 注释
/**
* 内容段落
*/
export interface ContentSection {
/** 段落 ID */
id: string;
/** 段落标题 */
title: string;
/** 段落内容 */
content: string;
/** 段落类型 */
type: SectionType;
}
CodeExample 接口
typescript
/**
* 代码语言类型
*/
export type CodeLanguage =
| 'javascript'
| 'typescript'
| 'jsx'
| 'tsx'
| 'css'
| 'json'
| 'bash'
| 'html'
| 'text';
/**
* 代码示例
*/
export interface CodeExample {
/** 示例 ID */
id: string;
/** 示例标题 */
title: string;
/** 代码内容 */
code: string;
/** 代码语言 */
language: CodeLanguage;
/** 代码解释 */
explanation: string;
/** 是否可编辑(在调试器中) */
isEditable: boolean;
}
TOCItem 接口
typescript
/**
* 目录项
*/
export interface TOCItem {
/** 目录项 ID */
id: string;
/** 目录标题 */
title: string;
/** 层级(1-3) */
level: number;
}
6.4 用户进度数据模型
UserProgress 接口
typescript
/**
* 用户进度
* 记录用户的学习状态和成就
*/
export interface UserProgress {
/** 已完成课程 ID 列表 */
completedLessons: string[];
/** 已完成模块 ID 列表 */
completedModules: string[];
/** 当前学习课程 ID */
currentLesson: string | null;
/** 连续学习天数 */
learningStreak: number;
/** 最后学习日期(YYYY-MM-DD) */
lastStudyDate: string;
/** 总学习时长(分钟) */
totalStudyTime: number;
/** 获得的徽章列表 */
badges: Badge[];
}
/**
* 默认用户进度
*/
export const DEFAULT_USER_PROGRESS: UserProgress = {
completedLessons: [],
completedModules: [],
currentLesson: null,
learningStreak: 0,
lastStudyDate: '',
totalStudyTime: 0,
badges: []
};
Badge 接口
typescript
/**
* 徽章类别
*/
export type BadgeCategory =
| 'progress' // 进度类
| 'streak' // 连续学习类
| 'quiz' // 测验类
| 'project'; // 项目类
/**
* 成就徽章
*/
export interface Badge {
/** 徽章 ID */
id: string;
/** 徽章名称 */
name: string;
/** 徽章描述 */
description: string;
/** 徽章图标 */
icon: string;
/** 获得日期 */
earnedDate: string;
/** 徽章类别 */
category: BadgeCategory;
}
Bookmark 接口
typescript
/**
* 收藏
*/
export interface Bookmark {
/** 课程 ID */
lessonId: string;
/** 模块 ID */
moduleId: string;
/** 添加时间 */
addedAt: string;
}
6.5 测验相关数据模型
Quiz 接口
typescript
/**
* 测验
*/
export interface Quiz {
/** 测验 ID */
id: string;
/** 所属模块 ID */
moduleId: string;
/** 所属课程 ID(可选) */
lessonId?: string;
/** 测验标题 */
title: string;
/** 题目列表 */
questions: QuizItem[];
/** 及格分数(百分制) */
passingScore: number;
/** 时间限制(秒,可选) */
timeLimit?: number;
}
QuizItem 接口
typescript
/**
* 测验题目
*/
export interface QuizItem {
/** 题目 ID */
id: string;
/** 题目内容 */
question: string;
/** 选项列表(通常 4 个) */
options: string[];
/** 正确答案索引(0-3) */
correctAnswer: number;
/** 答案解析 */
explanation: string;
/** 代码片段(可选) */
codeSnippet?: string;
}
QuizResult 接口
typescript
/**
* 测验结果
*/
export interface QuizResult {
/** 测验 ID */
quizId: string;
/** 得分(百分制) */
score: number;
/** 总题数 */
totalQuestions: number;
/** 是否通过 */
passed: boolean;
/** 用户答案列表 */
answers: number[];
/** 完成时间 */
completedAt: string;
/** 用时(秒) */
timeSpent: number;
}
面试题相关模型
typescript
/**
* 面试题难度
*/
export type InterviewDifficulty = 'easy' | 'medium' | 'hard';
/**
* 面试题目
*/
export interface InterviewQuestion {
/** 题目 ID */
id: string;
/** 所属模块 ID */
moduleId: string;
/** 模块名称 */
moduleName: string;
/** 题目内容 */
question: string;
/** 选项列表 */
options: string[];
/** 正确答案索引 */
correctAnswer: number;
/** 答案解析 */
explanation: string;
/** 难度等级 */
difficulty: InterviewDifficulty;
/** 代码片段(可选) */
codeSnippet?: string;
}
/**
* 错题记录
*/
export interface WrongAnswerRecord {
/** 题目 ID */
questionId: string;
/** 完整题目信息 */
question: InterviewQuestion;
/** 用户的错误答案 */
userAnswer: number;
/** 正确答案 */
correctAnswer: number;
/** 记录时间 */
recordedAt: string;
/** 尝试次数 */
attemptCount: number;
/** 是否已掌握 */
isMastered: boolean;
/** 最后尝试时间 */
lastAttemptAt: string;
}
/**
* 答题统计
*/
export interface QuizStatistics {
/** 总答题数 */
totalAnswered: number;
/** 正确数 */
correctCount: number;
/** 错误数 */
wrongCount: number;
/** 正确率(0-100) */
accuracyRate: number;
/** 各模块统计 */
moduleStats: Record<string, ModuleQuizStats>;
/** 最后更新时间 */
lastUpdated: string;
}
/**
* 模块答题统计
*/
export interface ModuleQuizStats {
moduleId: string;
moduleName: string;
totalQuestions: number;
answeredCount: number;
correctCount: number;
accuracyRate: number;
}
/**
* 默认答题统计
*/
export const DEFAULT_QUIZ_STATISTICS: QuizStatistics = {
totalAnswered: 0,
correctCount: 0,
wrongCount: 0,
accuracyRate: 0,
moduleStats: {},
lastUpdated: ''
};
6.6 其他辅助模型
SearchResult 接口
typescript
/**
* 搜索结果
*/
export interface SearchResult {
/** 结果类型 */
type: 'module' | 'lesson';
/** ID */
id: string;
/** 标题 */
title: string;
/** 描述 */
description: string;
/** 匹配的文本 */
matchedText: string;
/** 模块 ID(课程结果时) */
moduleId?: string;
/** 模块标题 */
moduleTitle?: string;
/** 难度 */
difficulty?: DifficultyType;
}
DailyQuestion 接口
typescript
/**
* 每日一题
*/
export interface DailyQuestion {
/** 日期(YYYY-MM-DD) */
date: string;
/** 题目 */
question: QuizItem;
/** 来源模块 ID */
moduleId: string;
/** 来源课程 ID */
lessonId: string;
/** 是否已回答 */
answered: boolean;
/** 是否回答正确 */
correct?: boolean;
}
6.7 实操:完成 Models.ets 文件
现在,让我们将所有数据模型整合到一个完整的文件中。
更新 entry/src/main/ets/models/Models.ets:
typescript
/**
* 数据模型定义
* React 教程应用的所有类型接口
*/
// ==================== 基础类型 ====================
export type DifficultyType = 'beginner' | 'basic' | 'intermediate' | 'advanced' | 'ecosystem';
export type CodeLanguage = 'javascript' | 'typescript' | 'jsx' | 'tsx' | 'css' | 'json' | 'bash' | 'html' | 'text';
export type SectionType = 'text' | 'code' | 'tip' | 'warning' | 'note';
export type BadgeCategory = 'progress' | 'streak' | 'quiz' | 'project';
export type InterviewDifficulty = 'easy' | 'medium' | 'hard';
// ==================== 学习模块 ====================
export interface LearningModule {
id: string;
title: string;
description: string;
difficulty: DifficultyType;
icon: string;
color: string;
lessonCount: number;
estimatedTime: string;
prerequisites: string[];
lessons: Lesson[];
}
export interface Lesson {
id: string;
moduleId: string;
title: string;
description: string;
order: number;
content: LessonContent;
hasPlayground: boolean;
hasQuiz: boolean;
}
export interface LessonContent {
sections: ContentSection[];
codeExamples: CodeExample[];
tableOfContents: TOCItem[];
keyTakeaways: string[];
}
export interface ContentSection {
id: string;
title: string;
content: string;
type: SectionType;
}
export interface CodeExample {
id: string;
title: string;
code: string;
language: CodeLanguage;
explanation: string;
isEditable: boolean;
}
export interface TOCItem {
id: string;
title: string;
level: number;
}
// ==================== 用户进度 ====================
export interface UserProgress {
completedLessons: string[];
completedModules: string[];
currentLesson: string | null;
learningStreak: number;
lastStudyDate: string;
totalStudyTime: number;
badges: Badge[];
}
export interface Badge {
id: string;
name: string;
description: string;
icon: string;
earnedDate: string;
category: BadgeCategory;
}
export interface Bookmark {
lessonId: string;
moduleId: string;
addedAt: string;
}
export const DEFAULT_USER_PROGRESS: UserProgress = {
completedLessons: [],
completedModules: [],
currentLesson: null,
learningStreak: 0,
lastStudyDate: '',
totalStudyTime: 0,
badges: []
};
// ==================== 测验相关 ====================
export interface Quiz {
id: string;
moduleId: string;
lessonId?: string;
title: string;
questions: QuizItem[];
passingScore: number;
timeLimit?: number;
}
export interface QuizItem {
id: string;
question: string;
options: string[];
correctAnswer: number;
explanation: string;
codeSnippet?: string;
}
export interface QuizResult {
quizId: string;
score: number;
totalQuestions: number;
passed: boolean;
answers: number[];
completedAt: string;
timeSpent: number;
}
export interface DailyQuestion {
date: string;
question: QuizItem;
moduleId: string;
lessonId: string;
answered: boolean;
correct?: boolean;
}
// ==================== 面试题库 ====================
export interface InterviewQuestion {
id: string;
moduleId: string;
moduleName: string;
question: string;
options: string[];
correctAnswer: number;
explanation: string;
difficulty: InterviewDifficulty;
codeSnippet?: string;
}
export interface WrongAnswerRecord {
questionId: string;
question: InterviewQuestion;
userAnswer: number;
correctAnswer: number;
recordedAt: string;
attemptCount: number;
isMastered: boolean;
lastAttemptAt: string;
}
export interface QuizStatistics {
totalAnswered: number;
correctCount: number;
wrongCount: number;
accuracyRate: number;
moduleStats: Record<string, ModuleQuizStats>;
lastUpdated: string;
}
export interface ModuleQuizStats {
moduleId: string;
moduleName: string;
totalQuestions: number;
answeredCount: number;
correctCount: number;
accuracyRate: number;
}
export const DEFAULT_QUIZ_STATISTICS: QuizStatistics = {
totalAnswered: 0,
correctCount: 0,
wrongCount: 0,
accuracyRate: 0,
moduleStats: {},
lastUpdated: ''
};
// ==================== 搜索 ====================
export interface SearchResult {
type: 'module' | 'lesson';
id: string;
title: string;
description: string;
matchedText: string;
moduleId?: string;
moduleTitle?: string;
difficulty?: DifficultyType;
}
本次课程小结
通过本次课程,你已经:
✅ 理解了数据模型设计原则
✅ 设计了学习模块的完整数据结构
✅ 实现了课程内容的数据模型
✅ 完成了用户进度数据模型
✅ 设计了测验和面试题相关模型
✅ 编写了完整的 Models.ets 文件
课后练习
-
扩展模型:为 UserProgress 添加学习目标相关字段
-
添加验证:编写函数验证 LearningModule 数据的完整性
-
类型守卫:编写类型守卫函数判断对象是否为特定接口类型
下次预告
第7次:本地数据持久化
我们将深入学习数据持久化:
- Preferences 存储详解
- StorageUtil 工具类完善
- 异步存储操作
- 数据迁移与版本管理
让应用数据能够持久保存!