主要功能: - ✅ 完成Book模型(电子书基本信息管理) - ✅ 完成Highlight模型(文本高亮功能) - ✅ 建立Flutter数据模型设计标准 技术特点: - 采用不可变对象设计模式 - 实现完整的序列化支持(toMap/fromMap) - 提供便利的工厂构造函数 - 正确处理枚举类型序列化 - 完善的空值安全处理 学习文档: - 📚 项目结构与环境配置指南 - 🎯 数据模型设计思路分析 - 💡 Flutter数据模型最佳实践 下一步: - 实现Annotation批注模型 - 设计本地存储方案 - 开始UI组件开发 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
6.4 KiB
6.4 KiB
Flutter 数据模型实践与技巧
一、已完成的数据模型
1. Book(书籍模型)✅
核心功能:
- 电子书基本信息管理(书名、作者、文件格式等)
- 阅读状态跟踪(阅读中、已完成、待阅读)
- 文件信息存储(路径、大小、格式)
- 扩展信息支持(标签、评分、简介)
设计亮点:
- 使用
BookFormat和ReadingStatus枚举确保类型安全 - 提供
Book.create()工厂方法简化对象创建 - 完整的序列化支持(toMap/fromMap)
- 不可变对象设计,所有字段使用final
2. Highlight(高亮模型)✅
核心功能:
- 文本高亮记录(选中文本、位置范围)
- 多颜色分类支持(5种颜色对应不同用途)
- 章节关联(chapterId可选)
- 时间戳记录
设计亮点:
HighlightColor枚举提供语义化颜色分类Highlight.create()工厂方法提供默认颜色textLength计算属性获取高亮长度isInRange()方法检查高亮范围
二、Flutter数据模型设计最佳实践
1. 不可变对象模式
class Book {
final String title; // 所有字段都是final
// 通过copyWith创建新对象,而不是修改原对象
Book copyWith({String? title}) {
return Book(title: title ?? this.title);
}
}
优势:
- 🔒 线程安全
- 🔄 状态管理友好(Flutter状态管理依赖对象比较)
- 🐛 减少意外修改bug
2. 空值安全设计
final String title; // 必需字段
final String? author; // 可为null的字段
final List<String> tags = const []; // 默认空列表,避免null
关键符号:
final:字段只能在构造函数中赋值?:字段可以为nullrequired:构造函数必需参数const []:不可变空列表
3. 枚举的正确使用
enum BookFormat { epub, mobi, txt, pdf }
// 存储时:枚举 → 字符串
'format': format.name, // "epub"
// 读取时:字符串 → 枚举
format: BookFormat.values.firstWhere((e) => e.name == "epub")
4. 工厂构造函数模式
// 便利构造函数
factory Book.create({
required String title,
required String filePath,
// 自动生成字段
}) {
return Book(
id: _generateId(), // 自动生成ID
addedDate: DateTime.now(), // 自动设置时间
status: ReadingStatus.pending, // 默认状态
title: title,
filePath: filePath,
// ...
);
}
设计原则:
- 自动生成ID和时间戳
- 为常用参数提供默认值
- 封装复杂的创建逻辑
5. 完整的对象生命周期管理
class Book {
// 构造函数
const Book({required this.title});
// 创建便利方法
factory Book.create({...}) { ... }
// 修改方法
Book copyWith({...}) { ... }
// 序列化方法
Map<String, dynamic> toMap() { ... }
factory Book.fromMap(Map<String, dynamic> map) { ... }
// 调试方法
String toString() { ... }
// 比较方法
bool operator ==(Object other) { ... }
int get hashCode => ...;
}
三、常见陷阱与解决方案
1. 枚举序列化错误
// ❌ 错误:直接存储枚举对象
'format': format, // 会导致序列化失败
// ✅ 正确:转换为字符串
'format': format.name,
// 读取时反向转换
format: BookFormat.values.firstWhere((e) => e.name == map['format'])
2. copyWith方法遗漏字段
// ❌ 错误:遗漏了chapterId参数
Highlight copyWith({String? bookId, ...}) {
return Highlight(
bookId: bookId ?? this.bookId,
// 缺少 chapterId 参数
);
}
// ✅ 正确:包含所有字段
Highlight copyWith({String? bookId, String? chapterId, ...}) {
return Highlight(
bookId: bookId ?? this.bookId,
chapterId: chapterId ?? this.chapterId, // 确保完整性
);
}
3. 工厂方法参数设计错误
// ❌ 错误:要求用户传入自动生成的字段
factory Highlight.create({
required String id, // 用户不应该手动传入ID
required DateTime createdTime, // 应该自动生成
// ...
});
// ✅ 正确:只要求用户必须提供的字段
factory Highlight.create({
required String bookId,
required String selectedText,
HighlightColor color = HighlightColor.yellow, // 提供默认值
String? chapterId,
}) {
return Highlight(
id: _generateId(), // 自动生成
createdTime: DateTime.now(), // 自动设置
// ...
);
}
四、性能优化技巧
1. 字符串插值优于字符串拼接
// ❌ 性能较差
return 'Book(id: ' + id + ', title: ' + title + ')';
// ✅ 性能更好
return 'Book(id: $id, title: $title)';
2. 避免重复计算
class Highlight {
// ❌ 每次调用都重新计算
int getTextLength() => endIndex - startIndex;
// ✅ 使用getter缓存计算结果
int get textLength => endIndex - startIndex;
}
3. 合理使用const构造函数
// 对于常量值使用const
static const List<String> emptyList = [];
// 构造函数标记为const
const Book({required this.title});
五、调试与测试技巧
1. 有意义的toString实现
@override
String toString() {
return 'Book(id: $id, title: $title, format: $format)';
}
2. 完整的对象比较
@override
bool operator ==(Object other) {
if (identical(this, other)) return true; // 先检查引用相等
return other is Book && other.id == id; // 再检查关键字段
}
@override
int get hashCode => id.hashCode; // 基于相同字段生成
六、下一步计划
待完成的模型:
- Annotation(批注模型) - 处理用户笔记和感想
- Bookmark(书签模型) - 管理阅读位置标记
- Bookshelf(书架模型) - 书籍分类管理
- ReadingProgress(阅读进度模型) - 跟踪阅读进度
待学习的技术:
- 本地存储方案 - Hive数据库集成
- Repository模式 - 数据访问层设计
- 状态管理 - Provider/Riverpod集成
- 文件处理 - EPUB/MOBI解析
七、代码质量检查清单
✅ 数据模型检查清单:
- 所有字段使用final
- 正确使用空值安全语法(?和required)
- 实现copyWith方法并包含所有字段
- 正确的序列化(枚举转换)
- 提供工厂方法简化创建
- 重写toString、equals、hashCode
- 添加有意义的文档注释
- 提供默认值避免null
- 使用计算属性优化性能