及时做APP开发实战(一)-MVVM架构设计实践本文将详细介绍如何在HarmonyOS NEXT应用中实现MVVM架构以及时做番茄待办应用为例展示分层设计的最佳实践。一、为什么选择MVVM架构在移动应用开发中良好的架构设计是项目可维护性和扩展性的基石。MVVMModel-View-ViewModel模式通过清晰的职责分离让代码更易于理解和维护。1.1 传统开发模式的痛点很多初学者习惯将所有代码写在页面组件中导致代码臃肿一个文件动辄上千行难以测试业务逻辑与UI耦合复用困难相同逻辑重复编写维护成本高修改一处影响多处1.2 MVVM的优势MVVM模式通过三层分离解决了上述问题┌─────────────────────────────────────┐ │ View视图层 │ │ 负责UI展示和用户交互 │ └──────────────┬──────────────────────┘ │ 数据绑定 ┌──────────────▼──────────────────────┐ │ ViewModel业务逻辑层 │ │ 负责业务处理和状态管理 │ └──────────────┬──────────────────────┘ │ 数据操作 ┌──────────────▼──────────────────────┐ │ Model数据模型层 │ │ 负责数据定义和存储 │ └─────────────────────────────────────┘【图1MVVM架构层次示意图】二、项目结构设计在及时做应用中我们采用以下目录结构entry/src/main/ets/ ├── model/ # 数据模型层 │ ├── TodoItem.ets # 待办任务模型 │ └── PomodoroRecord.ets # 番茄钟记录模型 ├── viewmodel/ # 业务逻辑层 │ ├── TodoViewModel.ets # 待办业务管理 │ └── PomodoroViewModel.ets # 番茄钟业务管理 ├── utils/ # 工具类层 │ ├── PreferencesHelper.ets # 持久化服务 │ └── CommonUtil.ets # 通用工具 └── pages/ # UI页面层 └── Index.ets # 主页面这种结构清晰明了每层职责分明model定义数据结构不包含业务逻辑viewmodel处理业务逻辑协调model和viewutils提供通用功能如存储、格式化等pages负责UI渲染和用户交互【图2项目目录结构截图】三、Model层设计Model层是数据的基础我们使用ArkTS的interface定义数据结构。3.1 待办任务模型/** * 待办任务数据模型 */exportinterfaceTodoItem{/** 唯一标识使用时间戳生成 */id:number;/** 任务文本内容 */text:string;/** 完成状态 */completed:boolean;/** 创建时间戳 */createdAt:number;/** 番茄钟完成次数 */pomodoroCount:number;}/** * 创建新的待办任务 */exportfunctioncreateTodoItem(text:string):TodoItem{return{id:Date.now(),text:text,completed:false,createdAt:Date.now(),pomodoroCount:0};}设计要点使用interface而非classArkTS推荐使用interface定义纯数据结构语义化命名每个字段都有清晰的注释说明工厂函数提供createTodoItem简化对象创建时间戳ID使用Date.now()生成唯一标识3.2 番茄钟记录模型/** * 番茄钟记录数据模型 */exportinterfacePomodoroRecord{/** 唯一标识 */id:number;/** 关联的待办任务ID */todoId:number;/** 单次专注时长分钟 */duration:number;/** 完成时间戳 */completedAt:number;}/** * 创建新的番茄钟记录 */exportfunctioncreatePomodoroRecord(todoId:number,duration:number):PomodoroRecord{return{id:Date.now(),todoId:todoId,duration:duration,completedAt:Date.now()};}注意todoId字段的设计它建立了番茄钟记录与待办任务的关联关系这是关系型数据建模的关键。四、ViewModel层实现ViewModel是MVVM的核心它承上启下既管理数据又为View提供服务。4.1 待办业务管理import{TodoItem,createTodoItem}from../model/TodoItem;import{PreferencesHelper}from../utils/PreferencesHelper;/** * 待办任务业务逻辑管理类 */exportclassTodoViewModel{privatepreferencesHelper:PreferencesHelper|nullnull;privatetodoList:TodoItem[][];/** * 初始化ViewModel */asyncinit():Promisevoid{this.preferencesHelperawaitPreferencesHelper.getInstance();awaitthis.loadTodoList();}/** * 加载待办列表 */privateasyncloadTodoList():Promisevoid{if(this.preferencesHelper){this.todoListawaitthis.preferencesHelper.getTodoList();}}/** * 添加新待办 */asyncaddTodo(text:string):PromiseTodoItem{consttodocreateTodoItem(text);this.todoList.push(todo);if(this.preferencesHelper){awaitthis.preferencesHelper.addTodo(todo);}returntodo;}/** * 切换待办完成状态 */asynctoggleTodoComplete(todoId:number):Promisevoid{consttodothis.todoList.find(itemitem.idtodoId);if(todo){todo.completed!todo.completed;awaitthis.updateTodo(todo);}}/** * 获取未完成的待办数量 */getActiveTodoCount():number{returnthis.todoList.filter(item!item.completed).length;}}【图3主页图】4.2 设计要点解析异步初始化init方法使用async/await处理异步加载内存缓存todoList保持内存中的数据减少IO操作单一职责每个方法只做一件事错误处理通过null检查避免空指针异常4.3 番茄钟业务管理exportclassPomodoroViewModel{privatepreferencesHelper:PreferencesHelper|nullnull;privatetodoViewModel:TodoViewModel|nullnull;privaterecords:PomodoroRecord[][];// 番茄钟配置privatestaticreadonlyDEFAULT_DURATION25;privatestaticreadonlySHORT_BREAK5;privatestaticreadonlyLONG_BREAK15;/** * 完成一次番茄钟 */asynccompletePomodoro(todoId:number,duration:numberPomodoroViewModel.DEFAULT_DURATION):PromisePomodoroRecord{constrecordcreatePomodoroRecord(todoId,duration);this.records.push(record);if(this.preferencesHelper){awaitthis.preferencesHelper.addPomodoroRecord(record);}// 更新待办的番茄钟完成次数if(this.todoViewModel){awaitthis.todoViewModel.incrementPomodoroCount(todoId);}returnrecord;}/** * 获取今日专注总时长 */getTodayTotalDuration():number{consttodaynewDate();today.setHours(0,0,0,0);consttodayTimestamptoday.getTime();returnthis.records.filter(recordrecord.completedAttodayTimestamp).reduce((total,record)totalrecord.duration,0);}}这里体现了ViewModel之间的协作PomodoroViewModel需要通知TodoViewModel更新番茄钟计数。五、View层使用示例在页面组件中我们通过ViewModel获取和操作数据import{TodoViewModel}from../viewmodel/TodoViewModel;EntryComponentstruct Index{StatetodoList:TodoItem[][];privatetodoViewModel:TodoViewModelnewTodoViewModel();asyncaboutToAppear(){awaitthis.todoViewModel.init();this.todoListthis.todoViewModel.getTodoList();}build(){Column(){// UI渲染ForEach(this.todoList,(todo:TodoItem){Text(todo.text).onClick(async(){awaitthis.todoViewModel.toggleTodoComplete(todo.id);this.todoListthis.todoViewModel.getTodoList();})})}}}关键点生命周期初始化在aboutToAppear中初始化ViewModel状态管理使用State装饰器实现响应式更新数据绑定UI直接绑定ViewModel的数据六、架构优势总结通过MVVM架构我们实现了代码组织清晰每层职责明确易于定位代码可测试性强ViewModel可以独立测试不依赖UI复用性好ViewModel可在多个页面复用维护成本低修改业务逻辑不影响UI结构在HarmonyOS NEXT开发中MVVM模式与ArkUI的响应式特性完美契合是构建高质量应用的理想选择。七、最佳实践建议保持Model纯粹只定义数据结构不包含业务逻辑ViewModel单一职责一个ViewModel管理一类业务合理使用工具类通用功能抽取到utils层异步处理规范统一使用async/await处理异步操作错误处理完善关键操作添加try-catch和null检查通过这套架构及时做应用具备了良好的可扩展性为后续功能开发打下了坚实基础。
及时做APP开发实战(一)-MVVM架构设计实践
及时做APP开发实战(一)-MVVM架构设计实践本文将详细介绍如何在HarmonyOS NEXT应用中实现MVVM架构以及时做番茄待办应用为例展示分层设计的最佳实践。一、为什么选择MVVM架构在移动应用开发中良好的架构设计是项目可维护性和扩展性的基石。MVVMModel-View-ViewModel模式通过清晰的职责分离让代码更易于理解和维护。1.1 传统开发模式的痛点很多初学者习惯将所有代码写在页面组件中导致代码臃肿一个文件动辄上千行难以测试业务逻辑与UI耦合复用困难相同逻辑重复编写维护成本高修改一处影响多处1.2 MVVM的优势MVVM模式通过三层分离解决了上述问题┌─────────────────────────────────────┐ │ View视图层 │ │ 负责UI展示和用户交互 │ └──────────────┬──────────────────────┘ │ 数据绑定 ┌──────────────▼──────────────────────┐ │ ViewModel业务逻辑层 │ │ 负责业务处理和状态管理 │ └──────────────┬──────────────────────┘ │ 数据操作 ┌──────────────▼──────────────────────┐ │ Model数据模型层 │ │ 负责数据定义和存储 │ └─────────────────────────────────────┘【图1MVVM架构层次示意图】二、项目结构设计在及时做应用中我们采用以下目录结构entry/src/main/ets/ ├── model/ # 数据模型层 │ ├── TodoItem.ets # 待办任务模型 │ └── PomodoroRecord.ets # 番茄钟记录模型 ├── viewmodel/ # 业务逻辑层 │ ├── TodoViewModel.ets # 待办业务管理 │ └── PomodoroViewModel.ets # 番茄钟业务管理 ├── utils/ # 工具类层 │ ├── PreferencesHelper.ets # 持久化服务 │ └── CommonUtil.ets # 通用工具 └── pages/ # UI页面层 └── Index.ets # 主页面这种结构清晰明了每层职责分明model定义数据结构不包含业务逻辑viewmodel处理业务逻辑协调model和viewutils提供通用功能如存储、格式化等pages负责UI渲染和用户交互【图2项目目录结构截图】三、Model层设计Model层是数据的基础我们使用ArkTS的interface定义数据结构。3.1 待办任务模型/** * 待办任务数据模型 */exportinterfaceTodoItem{/** 唯一标识使用时间戳生成 */id:number;/** 任务文本内容 */text:string;/** 完成状态 */completed:boolean;/** 创建时间戳 */createdAt:number;/** 番茄钟完成次数 */pomodoroCount:number;}/** * 创建新的待办任务 */exportfunctioncreateTodoItem(text:string):TodoItem{return{id:Date.now(),text:text,completed:false,createdAt:Date.now(),pomodoroCount:0};}设计要点使用interface而非classArkTS推荐使用interface定义纯数据结构语义化命名每个字段都有清晰的注释说明工厂函数提供createTodoItem简化对象创建时间戳ID使用Date.now()生成唯一标识3.2 番茄钟记录模型/** * 番茄钟记录数据模型 */exportinterfacePomodoroRecord{/** 唯一标识 */id:number;/** 关联的待办任务ID */todoId:number;/** 单次专注时长分钟 */duration:number;/** 完成时间戳 */completedAt:number;}/** * 创建新的番茄钟记录 */exportfunctioncreatePomodoroRecord(todoId:number,duration:number):PomodoroRecord{return{id:Date.now(),todoId:todoId,duration:duration,completedAt:Date.now()};}注意todoId字段的设计它建立了番茄钟记录与待办任务的关联关系这是关系型数据建模的关键。四、ViewModel层实现ViewModel是MVVM的核心它承上启下既管理数据又为View提供服务。4.1 待办业务管理import{TodoItem,createTodoItem}from../model/TodoItem;import{PreferencesHelper}from../utils/PreferencesHelper;/** * 待办任务业务逻辑管理类 */exportclassTodoViewModel{privatepreferencesHelper:PreferencesHelper|nullnull;privatetodoList:TodoItem[][];/** * 初始化ViewModel */asyncinit():Promisevoid{this.preferencesHelperawaitPreferencesHelper.getInstance();awaitthis.loadTodoList();}/** * 加载待办列表 */privateasyncloadTodoList():Promisevoid{if(this.preferencesHelper){this.todoListawaitthis.preferencesHelper.getTodoList();}}/** * 添加新待办 */asyncaddTodo(text:string):PromiseTodoItem{consttodocreateTodoItem(text);this.todoList.push(todo);if(this.preferencesHelper){awaitthis.preferencesHelper.addTodo(todo);}returntodo;}/** * 切换待办完成状态 */asynctoggleTodoComplete(todoId:number):Promisevoid{consttodothis.todoList.find(itemitem.idtodoId);if(todo){todo.completed!todo.completed;awaitthis.updateTodo(todo);}}/** * 获取未完成的待办数量 */getActiveTodoCount():number{returnthis.todoList.filter(item!item.completed).length;}}【图3主页图】4.2 设计要点解析异步初始化init方法使用async/await处理异步加载内存缓存todoList保持内存中的数据减少IO操作单一职责每个方法只做一件事错误处理通过null检查避免空指针异常4.3 番茄钟业务管理exportclassPomodoroViewModel{privatepreferencesHelper:PreferencesHelper|nullnull;privatetodoViewModel:TodoViewModel|nullnull;privaterecords:PomodoroRecord[][];// 番茄钟配置privatestaticreadonlyDEFAULT_DURATION25;privatestaticreadonlySHORT_BREAK5;privatestaticreadonlyLONG_BREAK15;/** * 完成一次番茄钟 */asynccompletePomodoro(todoId:number,duration:numberPomodoroViewModel.DEFAULT_DURATION):PromisePomodoroRecord{constrecordcreatePomodoroRecord(todoId,duration);this.records.push(record);if(this.preferencesHelper){awaitthis.preferencesHelper.addPomodoroRecord(record);}// 更新待办的番茄钟完成次数if(this.todoViewModel){awaitthis.todoViewModel.incrementPomodoroCount(todoId);}returnrecord;}/** * 获取今日专注总时长 */getTodayTotalDuration():number{consttodaynewDate();today.setHours(0,0,0,0);consttodayTimestamptoday.getTime();returnthis.records.filter(recordrecord.completedAttodayTimestamp).reduce((total,record)totalrecord.duration,0);}}这里体现了ViewModel之间的协作PomodoroViewModel需要通知TodoViewModel更新番茄钟计数。五、View层使用示例在页面组件中我们通过ViewModel获取和操作数据import{TodoViewModel}from../viewmodel/TodoViewModel;EntryComponentstruct Index{StatetodoList:TodoItem[][];privatetodoViewModel:TodoViewModelnewTodoViewModel();asyncaboutToAppear(){awaitthis.todoViewModel.init();this.todoListthis.todoViewModel.getTodoList();}build(){Column(){// UI渲染ForEach(this.todoList,(todo:TodoItem){Text(todo.text).onClick(async(){awaitthis.todoViewModel.toggleTodoComplete(todo.id);this.todoListthis.todoViewModel.getTodoList();})})}}}关键点生命周期初始化在aboutToAppear中初始化ViewModel状态管理使用State装饰器实现响应式更新数据绑定UI直接绑定ViewModel的数据六、架构优势总结通过MVVM架构我们实现了代码组织清晰每层职责明确易于定位代码可测试性强ViewModel可以独立测试不依赖UI复用性好ViewModel可在多个页面复用维护成本低修改业务逻辑不影响UI结构在HarmonyOS NEXT开发中MVVM模式与ArkUI的响应式特性完美契合是构建高质量应用的理想选择。七、最佳实践建议保持Model纯粹只定义数据结构不包含业务逻辑ViewModel单一职责一个ViewModel管理一类业务合理使用工具类通用功能抽取到utils层异步处理规范统一使用async/await处理异步操作错误处理完善关键操作添加try-catch和null检查通过这套架构及时做应用具备了良好的可扩展性为后续功能开发打下了坚实基础。