[鸿蒙从零到一] HarmonyOS 架构实战:分层架构、MVVM 与状态驱动 UI
一、为什么需要架构模式
随着 HarmonyOS 应用复杂度提升,业务逻辑、UI 交互、数据流散落在各处,代码耦合严重、难以测试、维护成本高。架构模式通过分层解耦、职责分离、单向数据流,让代码更清晰、更可测、更易扩展。
二、分层架构:职责分离的基础
经典三层架构:
- UI 层:ArkUI 组件、用户交互、状态渲染
- 业务逻辑层(BLL):数据转换、业务规则、流程编排
- 数据访问层(DAL):网络请求、数据库操作、本地缓存
2.1 依赖方向与边界
// ❌ 反模式:UI 层直接访问数据库
@Component
struct BadExample {
async loadData() {
const db = relationalStore.getRdbStore(...) // UI 层不应知道数据库细节
}
}
// ✅ 正确:通过 Repository 隔离
export class UserRepository {
private db: relationalStore.RdbStore
async getUsers(): Promise<User[]> {
const result = await this.db.query('users')
return result.rows.map(row => new User(row))
}
}
@Component
struct GoodExample {
private repo = new UserRepository()
@State users: User[] = []
async aboutToAppear() {
this.users = await this.repo.getUsers() // UI 只关心业务对象
}
}
2.2 分层收益
- 每层可独立测试(Mock Repository 即可测试 UI 逻辑)
- 数据源切换对上层透明(数据库换 HTTP 接口,UI 无感知)
- 业务规则集中管理,避免散落在组件中
三、MVVM:状态与视图的双向绑定
MVVM(Model-View-ViewModel)将 UI 状态抽离到 ViewModel,通过数据绑定驱动视图更新。
3.1 结构拆解
- Model:纯数据对象(如
User、Product) - View:ArkUI 组件,只负责渲染和事件分发
- ViewModel:持有状态、处理交互逻辑、调用 Repository
3.2 完整示例
// Model
export class Todo {
constructor(public id: string, public text: string, public done: boolean) {}
}
// ViewModel
export class TodoViewModel {
@State todos: Todo[] = []
@State inputText: string = ''
private repo = new TodoRepository()
async loadTodos() {
this.todos = await this.repo.getAll()
}
async addTodo() {
if (!this.inputText.trim()) return
const newTodo = await this.repo.create(this.inputText)
this.todos = [...this.todos, newTodo]
this.inputText = ''
}
async toggleTodo(id: string) {
const todo = this.todos.find(t => t.id === id)
if (todo) {
todo.done = !todo.done
await this.repo.update(todo)
this.todos = [...this.todos] // 触发刷新
}
}
}
// View
@Component
struct TodoListView {
@State vm: TodoViewModel = new TodoViewModel()
aboutToAppear() {
this.vm.loadTodos()
}
build() {
Column() {
TextInput({ text: this.vm.inputText })
.onChange(v => this.vm.inputText = v)
Button('添加').onClick(() => this.vm.addTodo())
List() {
ForEach(this.vm.todos, (todo: Todo) => {
ListItem() {
Row() {
Checkbox().select(todo.done)
.onChange(() => this.vm.toggleTodo(todo.id))
Text(todo.text).decoration(todo.done ? TextDecorationType.LineThrough : TextDecorationType.None)
}
}
}, (todo: Todo) => todo.id)
}
}
}
}
3.3 MVVM 的优势与陷阱
优势:
- View 与业务逻辑解耦,易于替换 UI 框架
- ViewModel 可单元测试,无需启动 UI
- 状态集中管理,避免分散在各个组件
陷阱:
- ViewModel 膨胀:一个页面对应一个 ViewModel,复杂页面会有几百行状态管理代码
- 双向绑定滥用:
@Link过多导致数据流向不清晰 - 缺乏全局状态管理:跨页面共享状态需要额外设计(如 Singleton、EventBus)
四、状态驱动 UI:单向数据流
受 Redux/Vuex 启发,状态驱动 UI 强调单向数据流:Action → Reducer → State → View。
4.1 核心概念
- State:应用唯一的数据源(Single Source of Truth)
- Action:描述"发生了什么"的纯对象(如
{ type: 'ADD_TODO', text: '...' }) - Reducer:纯函数,接收旧 State 和 Action,返回新 State
- View:根据 State 渲染 UI,用户交互触发 Action
4.2 简化实现
// Action 定义
type Action =
| { type: 'ADD_TODO', text: string }
| { type: 'TOGGLE_TODO', id: string }
| { type: 'SET_TODOS', todos: Todo[] }
// State 定义
interface AppState {
todos: Todo[]
}
// Reducer
function todoReducer(state: AppState, action: Action): AppState {
switch (action.type) {
case 'ADD_TODO':
return { ...state, todos: [...state.todos, new Todo(Date.now().toString(), action.text, false)] }
case 'TOGGLE_TODO':
return {
...state,
todos: state.todos.map(t => t.id === action.id ? { ...t, done: !t.done } : t)
}
case 'SET_TODOS':
return { ...state, todos: action.todos }
default:
return state
}
}
// Store
class Store {
@State private state: AppState = { todos: [] }
dispatch(action: Action) {
this.state = todoReducer(this.state, action)
}
getState(): AppState {
return this.state
}
}
// View
@Component
struct TodoApp {
private store = new Store()
build() {
Column() {
Button('添加').onClick(() => this.store.dispatch({ type: 'ADD_TODO', text: '新任务' }))
List() {
ForEach(this.store.getState().todos, (todo: Todo) => {
ListItem() {
Text(todo.text).onClick(() => this.store.dispatch({ type: 'TOGGLE_TODO', id: todo.id }))
}
})
}
}
}
}
4.3 状态驱动的优势
- 数据流向清晰:Action → State → View,单向流动
- 时间旅行调试:记录所有 Action,可回溯任意状态
- 易于测试:Reducer 是纯函数,输入输出确定
五、架构模式选型矩阵
| 场景 | 推荐架构 | 原因 |
|---|---|---|
| 简单工具类应用 | 分层架构 | 无需复杂状态管理,三层足够 |
| 表单密集、交互复杂 | MVVM | ViewModel 集中管理表单状态 |
| 多页面共享状态 | 状态驱动 UI | 全局 Store 避免状态分散 |
| 实时协作、撤销重做 | 状态驱动 UI | Action 可序列化、可回放 |
六、实战建议
- 从分层开始:先建立 Repository → Service → ViewModel 的基础结构
- 状态提升:当多个组件共享状态时,提升到父组件或全局 Store
- 避免过度设计:小项目直接用
@State即可,不要为了架构而架构 - 测试驱动:关键业务逻辑写在 ViewModel/Reducer,保证可测试性
- 渐进式重构:遗留代码不要一次性重写,按模块逐步迁移
七、总结
架构模式不是银弹,而是工程实践的沉淀。分层架构提供职责分离的基础,MVVM 适合表单和交互密集的场景,状态驱动 UI 在复杂应用中提供清晰的数据流。选择架构模式时,优先考虑团队认知成本和项目复杂度,避免过度设计。

浙公网安备 33010602011771号