【HarmonyOS】MVVM与三层架构
文章目录
- 一、MVC 模式
- 1、概念
- 2、三大组件的职责与特性
- 2.1 Model(模型):数据与业务逻辑的核心
- 2.2 View(视图):用户界面的展示层
- 2.3 Controller(控制器):业务逻辑的调度层
- 3、交互流程
- 4、优缺点
- 4.1 优点
- 4.2 缺点
- 5、MVC 的适用场景
- 二、MVVM 模式
- 1、概念
- 2、三大组件的职责和特性
- 2.1 View:用户界面层
- 2.2 Model:数据访问层
- 2.3 ViewModel:表示逻辑层
- 3、架构原则
- 3.1 不可跨层访问
- 3.2 下层不可访问上层数据
- 3.3 非父子组件间不可直接访问
- 4、实战训练
- 4.1 文件结构说明
- 4.2 设计技巧
- 三、三层架构
- 1、三层架构核心概念与设计理念
- 2、各层详细职责与特性
- 2.1 commons(公共能力层):最底层的 “通用工具库”
- 核心定位
- 主要内容
- 编译部署
- 依赖规则
- 2.2 features(基础特性层):中间层的 “功能模块化单元”
- 核心定位
- 主要内容
- 编译部署
- 依赖规则
- 2.3 products(产品定制层):最上层的 “多设备定制入口”
- 核心定位
- 主要内容
- 编译与部署形态
- 依赖规则
- 3、搭建三层架构
- 3.1 创建目录
- 3.2 features(基础特性层)创建
- 3.3 common(公共能力层)创建
- 3.4 products层配置修改
MVC、MVVM等的目录组织方式,适用于单个模块内文件组织,提供代码的可读性和方向。
三层架构的方式对整个应用的功能进行模块化,实现高内聚、低耦合开发。
一、MVC 模式
1、概念
MVC(Model-View-Controller)是一种常见的软件设计模式,旨在通过分离数据处理、用户界面和业务逻辑,实现代码解耦、提高可维护性和可扩展性。
MVC 的本质是将应用程序的三个核心职责拆分为独立的三大组件,每个组件只负责单一功能,避免职责混杂。这种分离带来两大核心价值:
- 解耦:修改一个组件(如调整 UI 样式)时,无需改动其他组件(如数据处理逻辑);
- 复用:组件可独立复用(如同一套数据模型可对接不同视图,同一控制器可处理多个相似视图的交互)。
2、三大组件的职责与特性
2.1 Model(模型):数据与业务逻辑的核心
Model 是应用程序的 “数据层”,负责管理数据、处理业务规则、维护数据状态,不关心用户界面(View)的展示方式,也不依赖控制器(Controller)的交互逻辑。
- 核心职责:
- 数据存储与管理:封装数据(如用户信息、订单数据),提供数据访问接口(如获取用户列表、更新订单状态),可对接数据库、API 等数据源;
- 业务逻辑处理:实现核心业务规则(如用户注册时的合法性校验、订单结算时的价格计算);
- 状态通知:当数据发生变化时,通过 “观察者模式” 通知关联的 View(或 Controller),触发界面更新(部分实现中由 Controller 中转)。
- 特点:
- 无 UI 依赖:不包含任何与界面渲染相关的代码。
- 可测试性强:无需依赖 View 或 Controller,可直接通过单元测试验证业务逻辑。
2.2 View(视图):用户界面的展示层
View 是应用程序的 “界面层”,负责将 Model 中的数据以可视化形式呈现给用户,并接收用户的原始交互(如点击按钮、输入文本),但不处理业务逻辑。
- 核心职责:
- 数据渲染:根据 Model 提供的数据,渲染用户界面(如网页、App 页面、桌面窗口);
- 交互转发:将用户的操作(如点击 “添加用户” 按钮)转发给 Controller,由 Controller 处理后续逻辑;
- 响应更新:接收 Model(或 Controller)的通知,当数据变化时更新界面(如用户列表新增后,View 重新渲染列表)。
- 特点:
- 被动性:不主动处理业务逻辑,仅负责 “展示” 和 “转发交互”;
- 依赖 Model 数据:需从 Model 获取展示所需的数据,但不直接修改 Model(修改需通过 Controller)。
2.3 Controller(控制器):业务逻辑的调度层
Controller 是应用程序的 “逻辑层”,负责协调 Model 和 View 的交互,是连接两者的 “桥梁”,处理用户交互逻辑并调度 Model 的业务功能。
- 核心职责:
- 接收交互请求:接收 View 转发的用户操作(如 “添加用户” 请求);
- 调度 Model 处理业务:调用 Model 的接口完成业务逻辑(如调用
addUser
添加用户); - 更新 View 展示:在 Model 数据变化后,通知 View 重新渲染界面(或由 Model 直接通知 View,视实现而定);
- 参数校验与格式转换:对用户输入进行基础校验(如格式校验),并转换为 Model 可接受的格式。
- 特点:
- 协调者角色:不直接存储数据(数据在 Model),不直接渲染界面(界面在 View),仅负责 “调度”;
- 低耦合:仅依赖 Model 和 View 的接口,不侵入两者的内部实现。
3、交互流程
MVC 的三大组件通过固定的流程协同工作,以 “用户添加数据” 为例,完整交互流程如下:
- 用户交互:用户在 View(如网页)中输入姓名和年龄,点击 “添加” 按钮;
- View 转发请求:View 捕获点击事件,将输入的参数(姓名、年龄)转发给 Controller;
- Controller 调度业务:Controller 接收请求,先做基础参数校验(如年龄是否为数字),再调用 Model 的
addUser
方法处理业务; - Model 处理并通知:Model 执行
addUser
的业务逻辑(如合法性校验、存储数据),数据更新后通过 “观察者模式” 通知 View; - View 更新界面:View 接收 Model 的通知,调用 Controller 获取最新数据,重新渲染用户列表,完成界面更新。
流程简化图: 用户操作 → View → Controller → Model(数据变化)→ View(界面更新)
4、优缺点
4.1 优点
- 职责清晰,解耦性强:数据(Model)、界面(View)、逻辑(Controller)分离,便于单独维护和修改;
- 可扩展性高:新增功能时,可独立扩展某一组件(如新增 “用户详情 View”,无需修改 Model 和 Controller 核心逻辑);
- 可测试性强:Model 可独立单元测试,View 可通过模拟数据测试渲染,Controller 可模拟交互测试逻辑;
- 复用性好:同一 Model 可对接多个 View(如 “用户数据” 可同时在 “列表 View” 和 “详情 View” 中展示),同一 Controller 可处理多个相似 View 的交互。
4.2 缺点
- 结构复杂,学习成本高:对于简单应用(如静态网页),MVC 的三层结构会增加代码冗余和开发成本;
- Controller 可能过度臃肿:在复杂应用中,Controller 需协调大量 Model 和 View,容易成为 “万能组件”,导致逻辑冗余;
- View 与 Model 的间接依赖:部分实现中,View 仍需了解 Model 的数据结构(如渲染时需知道用户的
name
和age
字段),未完全解耦; - 不适合小型应用:小型项目(如工具类 App)使用 MVC 会显得 “大材小用”,降低开发效率。
5、MVC 的适用场景
MVC 并非 “万能架构”,需根据项目规模和复杂度选择:
- 适合场景:中大型应用(如企业管理系统、电商平台、复杂移动 App),需长期维护且团队分工明确(如专人负责 UI、专人负责业务逻辑);
- 不适合场景:小型静态应用(如个人博客、简单工具)、原型开发(需快速迭代),或功能单一的组件(如独立的表单组件)。
二、MVVM 模式
1、概念
MVVM 将应用分为Model、View和ViewModel三个核心部分,实现数据、视图与逻辑的分离。
ArkUI的UI开发模式就属于MVVM模式,通过对MVVM概念的基本介绍,开发者大致能猜到状态管理能在MVVM中起什么样的作用,状态管理旨在数据驱动更新,让开发者只用关注页面设计,而不去关注整个UI的刷新逻辑,数据的维护也无需开发者进行感知,由状态变量自动更新完成,而这就是属于ViewModel层所需要支持的内容,因此开发者使用MVVM模式开发自己的应用是最省心省力的。
2、三大组件的职责和特性
2.1 View:用户界面层
负责用户界面展示并与用户交互,不包含任何业务逻辑。它通过绑定ViewModel层提供的数据实现动态更新。
- 展示用户界面(如按钮、列表、表单);
- 接收用户交互(如点击、输入、滑动);
- 不包含业务逻辑,仅负责 “视图渲染” 和 “交互转发”。
2.2 Model:数据访问层
以数据为中心,不直接与用户界面交互。负责数据结构定义,数据管理(获取、存储、更新等),以及业务逻辑处理。
- 存储应用的核心数据(如用户信息、商品列表);
- 封装数据逻辑(如数据请求、本地存储、数据验证);
- 不依赖任何其他组件,仅关注 “数据本身”。
2.3 ViewModel:表示逻辑层
作为连接Model和View的桥梁,通常一个View对应一个ViewModel。View和
作为 View 与 Model 的 “中间层”,隔离视图与数据; 2. 封装视图相关的业务逻辑(如 “点击按钮后请求数据”“输入框内容验证”); 3. 维护 “视图状态”(如
isLoading
、isShowModal
),暴露给 View 可绑定的数据; 4. 监听 Model 数据变化,同步更新到 View; 5. 监听 View 交互,触发 Model 数据操作。
ViewModel有两种通信方式:
- 1.方法调用:View通过事件监听用户行为,在回调里面触发ViewModel层的方法。例如当View监听到用户Button点击行为,调用ViewModel对应的方法,处理用户操作。
- 2.双向绑定:View绑定ViewModel的数据,实现双向同步。
3、架构原则
3.1 不可跨层访问
- View层不可以直接调用Model层的数据,只能通过ViewModel提供的方法进行调用。
- Model层数据,不可以直接操作UI,Model层只能通知ViewModel层数据有更新,由ViewModel层更新对应的数据。
3.2 下层不可访问上层数据
下层数据通过通知模式更新上层数据。在业务逻辑中,下层不可直接获取上层数据。例如,ViewModel层的逻辑处理不应该依赖View层界面上的某个值。
3.3 非父子组件间不可直接访问
这是针对View层设计的核心原则,一个组件应该具备以下逻辑:
- 禁止直接访问父组件(必须使用事件或是订阅能力)。
- 禁止直接访问兄弟组件。这是因为组件应该仅能访问自己的子节点(通过传参)和父节点(通过事件或通知),以此完成组件之间的解耦。
4、实战训练
4.1 文件结构说明
- src
- ets
- pages ------ 存放页面组件
- views ------ 存放业务组件
- shares ------ 存放通用组件
- viewModel ------ 数据服务
- LoginViewModel ----- 登录页ViewModel
- xxxViewModel ------ 其他页ViewModel
- ets
4.2 设计技巧
Model层
- model层存放本应用核心数据结构,这层本身和UI开发关系不大,让用户按照自己的业务逻辑进行封装。
ViewModel层
注意:
ViewModel层不只是存放数据,它同时需要提供数据的服务及处理。
- ViewModel层是为视图服务的数据层。其设计具有两个特点:
- 按照页面组织数据。
- 每个页面数据进行懒加载。
View层
View层根据需要来组织,但View层需要区分一下三种组件:
- 页面组件:提供整体页面布局,实现多页面之间的跳转,前后台事件处理等页面内容。
- 业务组件:被页面引用,构建出页面。
- 共享组件:与项目无关的多项目共享组件。
共享组件和业务组件的区别:
业务组件包含了ViewModel数据,没有ViewModel,这个组件不能运行。
共享组件:不包含ViewModel层的数据,需要的数据从外部传入。共享组件包含一个自定义组件,只要外部参数(无业务参数)满足,就可以工作。
三、三层架构
鸿蒙(HarmonyOS)的三层架构是针对 模块化、可复用、可定制 的应用开发需求设计的分层模型,核心目标是解耦代码、提升复用效率、适配多设备形态(如手机、平板、手表、车机等)。其架构设计遵循 “高内聚、低耦合” 原则,通过明确的分层职责和依赖关系,支持大型应用的协同开发与灵活部署。
1、三层架构核心概念与设计理念
鸿蒙三层架构从下到上分为 commons(公共能力层)、features(基础特性层)、products(产品定制层),每层职责边界清晰,依赖关系严格单向(不允许反向依赖):
- 复用性优先:将全应用通用的能力(如工具类、配置)抽离到最底层,供上层任意复用,减少重复开发。
- 特性模块化:将应用的独立功能(如 “用户登录”“商品列表”)封装为可独立编译、可定制的特性模块,支持按需集成。
- 多设备适配:顶层针对不同设备形态(如手机、手表)定制产品包,底层能力与特性模块无需修改即可跨设备复用,降低多端开发成本。
- 依赖可控:严格限制依赖方向(commons ← features ← products),避免 “上层依赖下层、下层反向依赖上层” 导致的耦合混乱,便于后续维护与扩展。
2、各层详细职责与特性
2.1 commons(公共能力层):最底层的 “通用工具库”
核心定位
全应用 最基础、最通用的能力集合,不包含任何业务逻辑或设备相关的适配代码,是整个应用的 “基础设施”。用于存放公共基础能力集合(如工具库、公共配置等)。commons层可编译成一个或多个HAR包或HSP包,只可以被products和features依赖,不可以反向依赖。
主要内容
- 工具库:通用工具类(如字符串处理、日期格式化、网络请求封装、数据加密 / 解密、JSON 解析等)、常用常量(如接口地址前缀、错误码定义)。
- 公共配置:跨模块通用的配置项(如日志配置、主题色基础值、网络超时时间)、资源定义(如通用图标、公共字符串资源)。
- 基础模型:全应用通用的数据模型(如 “用户信息基类”“分页请求 / 响应基类”),不包含业务专属字段。
- 公共组件:无业务关联的通用 UI 组件(如 “加载中弹窗”“空数据提示组件”“通用按钮”),可在任意特性 / 产品中复用。
编译部署
- 编译为 HAR 包(HarmonyOS ArkUI 组件包) 或 HSP 包(HarmonyOS 共享包):
- HAR 包:包含代码、资源(如图片、字符串)的静态包,被依赖时会嵌入到依赖方的 HAP 中,适合小规模通用能力。
- HSP 包:可动态部署、共享的包,多个应用 / 模块可共用同一个 HSP 包,适合大规模通用能力(如公共工具库)。
依赖规则
- 只能被依赖,不能反向依赖:仅允许上层的
features
层和products
层依赖commons
层;commons
层不能依赖features
或products
层(避免耦合业务逻辑,确保通用性)。
2.2 features(基础特性层):中间层的 “功能模块化单元”
核心定位
应用的 业务特性集合,每个 feature
对应一个相对独立的功能模块(如 “首页轮播”“购物车”“个人中心”),具备完整的 “UI + 业务逻辑”,可独立开发、编译、测试。
主要内容
- 业务特性模块:每个模块高内聚(包含该功能所需的所有代码)、低耦合(与其他模块通过接口交互,不直接依赖内部实现)。例如:
- “登录模块”:包含登录页面 UI、登录接口调用、验证码逻辑、登录状态管理。
- “商品列表模块”:包含列表 UI、下拉刷新 / 上拉加载、商品筛选逻辑、商品数据模型(业务专属字段)。
- 特性间交互接口:若多个
feature
需交互(如 “购物车” 需调用 “用户登录” 的状态),通过定义 接口(interface) 实现,避免直接依赖模块内部代码(如 “登录模块” 暴露 “获取登录状态” 接口,“购物车” 通过接口调用,不依赖 “登录模块” 的具体实现)。
编译部署
根据是否需要 “独立部署”,分为两种形态:
- 非独立部署的 feature:编译为 HAR/HSP 包,作为 “组件” 被其他模块(如其他
feature
或products
层)依赖。例如 “通用弹窗提示” 特性,无独立入口,仅作为功能组件被调用。 - 独立部署的 feature:编译为 Feature 类型的 HAP 包(HarmonyOS 应用包),具备独立的能力(如后台服务、独立页面),但无应用主入口,需与
products
层的 “Entry 类型 HAP” 组合部署。例如 “地图服务” 特性,可独立运行后台定位,但需通过主应用(Entry HAP)启动。
依赖规则
- 可依赖下层,允许横向调用:
- 可依赖
commons
层(使用通用工具、配置); - 可横向依赖其他
feature
(但需通过接口,避免强耦合); - 禁止反向依赖上层:
features
层不能依赖products
层(避免耦合设备定制逻辑,确保特性模块可跨设备复用)。
- 可依赖
2.3 products(产品定制层):最上层的 “多设备定制入口”
核心定位
针对 不同设备形态或产品版本 的 “最终产品集成层”,负责将 features
层的特性模块按需组合,生成对应设备的 “可安装应用”,是应用的 主入口。
主要内容
- 设备定制配置:针对不同设备形态(如手机、平板、手表)的适配配置,例如:
- 屏幕尺寸适配(如手表端隐藏手机端的 “横向菜单”);
- 功能按需集成(如车机端集成 “导航” 特性,手表端不集成);
- 资源定制(如不同设备的启动页、主题色差异)。
- 应用主入口:每个
products
子目录对应一个设备的 “主应用”,包含 Entry 类型的 HAP 包(具备应用主入口,可独立安装启动),负责:- 应用启动逻辑(如初始化、权限申请);
- 页面路由管理(如主页面跳转、特性模块入口跳转);
- 设备专属功能集成(如手表端的 “健康数据同步” 入口)。
编译与部署形态
- 每个
products
子目录编译为 Entry 类型的 HAP 包:这是鸿蒙应用的 “主包”,具备独立的应用图标、启动入口,可直接安装到设备上运行。若需集成 “独立部署的 feature(Feature HAP)”,则将 Entry HAP 与 Feature HAP 组合为 “应用组”,一起部署到设备。
依赖规则
- 仅依赖下层,禁止横向调用:
- 可依赖
commons
层(使用通用工具)和features
层(集成特性模块); - 禁止横向依赖:不同
products
子目录(如 “手机端产品” 和 “手表端产品”)不能互相依赖(确保各设备产品独立,避免定制逻辑混乱); - 禁止被下层依赖:
products
层是最顶层,features
和commons
层不能依赖它(确保下层模块的通用性)。
- 可依赖
3、搭建三层架构
本文依据官网上的架构操作:
三层架构
3.1 创建目录
特性 | HAR(HarmonyOS ArkUI 组件包) | HSP(HarmonyOS 共享包) |
---|---|---|
集成方式 | 静态集成:编译时将 HAR 的代码、资源 “嵌入” 依赖方(如 HAP),最终生成一个完整包。 | 动态部署:HSP 是独立的包,可单独安装 / 更新,多个应用 / 模块可 “共享” 同一个 HSP 实例。 |
复用范围 | 仅依赖方内部使用,不对外共享(如 A 应用依赖的 HAR,B 应用无法复用)。 | 跨应用 / 跨模块共享(如系统级 HSP 可被多个应用依赖,避免重复安装)。 |
部署灵活性 | 依赖方打包时需包含 HAR,无法单独更新(更新 HAR 需重新打包依赖方)。 | 可独立更新(无需重新打包依赖方,如修复 HSP 中的 Bug,仅更新 HSP 即可)。 |
创建三个文件夹commons、features、products。同时把原目录的entry
模块移到products
目录。
完成后示例:
3.2 features(基础特性层)创建
HAR(Harmony Archive)是静态共享包:编译时打包到引用方的包中,HAR包是一个编译中间态产物,不是最终的运行实体。
- 若用 HSP:HSP 是独立部署的包,即使产品不需要某个 feature,若误依赖也会导致 HSP 被安装,增加设备存储占用;且 HSP 无法 “按需裁剪”(要么全依赖,要么全不依赖)。
- 若用 HAR:HAR 静态嵌入依赖方,
products
层仅集成需要的 feature 的 HAR,不需要的 feature 完全不参与编译,最终产品包中仅包含必要的业务代码,体积更精简。
创建时,选择Static Library。
3.3 common(公共能力层)创建
HSP(Harmony Shared Package)是动态共享包:运行时按需加载,多个模块共享同一份代码,减少包体积。
- 若用 HAR:每个依赖
common
的模块(如 “登录 feature”“购物车 feature”)都会将 HAR 代码嵌入自身包中,导致最终多个 HAP 包中存在重复的common
代码,增加应用整体体积。- 若用 HSP:
common
层编译为一个 HSP 包,所有模块共享同一个 HSP 实例,无需重复嵌入,大幅减少冗余(尤其对多 HAP 组合的应用,效果更明显)。
创建时,选择Shared Library。
这样就完成了基本的工程目录的搭建,接下来进行文件的位置调整。
3.4 products层配置修改
需要重新创建一个pages目录,用于应用的根页面,并新建一个page页面,在pages中右键新建一个empty page并命名为Index,此时自动在main_page.json中自动生成一个页面配置pages/Index,由于默认工程初始包含了Index页面(之前移入了quickstart模块中),在这里需要删除重复的页面配置。
在default模块下的oh-package.json5(products/entry/oh-package.json5)文件中配置依赖
{"name": "default","version": "1.0.0","description": "Please describe the basic information.","main": "","author": "","license": "","dependencies": {// 依赖"learning": "file:../../features/learning","map": "file:../../features/map","quickstart": "file:../../features/quickstart"}
}
// 其他同理