【HarmonyOS】MVVM与三层架构

文章目录

  • [一、MVC 模式](#一、MVC 模式)
    • 1、概念
    • 2、三大组件的职责与特性
      • [2.1 Model(模型):数据与业务逻辑的核心](#2.1 Model(模型):数据与业务逻辑的核心)
      • [2.2 View(视图):用户界面的展示层](#2.2 View(视图):用户界面的展示层)
      • [2.3 Controller(控制器):业务逻辑的调度层](#2.3 Controller(控制器):业务逻辑的调度层)
    • 3、交互流程
    • 4、优缺点
      • [4.1 优点](#4.1 优点)
      • [4.2 缺点](#4.2 缺点)
    • [5、MVC 的适用场景](#5、MVC 的适用场景)
  • [二、MVVM 模式](#二、MVVM 模式)
    • 1、概念
    • 2、三大组件的职责和特性
      • [2.1 View:用户界面层](#2.1 View:用户界面层)
      • [2.2 Model:数据访问层](#2.2 Model:数据访问层)
      • [2.3 ViewModel:表示逻辑层](#2.3 ViewModel:表示逻辑层)
    • 3、架构原则
      • [3.1 不可跨层访问](#3.1 不可跨层访问)
      • [3.2 下层不可访问上层数据](#3.2 下层不可访问上层数据)
      • [3.3 非父子组件间不可直接访问](#3.3 非父子组件间不可直接访问)
    • 4、实战训练
      • [4.1 文件结构说明](#4.1 文件结构说明)
      • [4.2 设计技巧](#4.2 设计技巧)
  • 三、三层架构

MVC、MVVM等的目录组织方式,适用于单个模块内文件组织,提供代码的可读性和方向。

三层架构的方式对整个应用的功能进行模块化,实现高内聚、低耦合开发。

一、MVC 模式

1、概念

MVC(Model-View-Controller)是一种常见的软件设计模式,旨在通过分离数据处理、用户界面和业务逻辑,实现代码解耦、提高可维护性和可扩展性。

MVC 的本质是将应用程序的三个核心职责拆分为独立的三大组件,每个组件只负责单一功能,避免职责混杂。这种分离带来两大核心价值:

  1. 解耦:修改一个组件(如调整 UI 样式)时,无需改动其他组件(如数据处理逻辑);
  2. 复用:组件可独立复用(如同一套数据模型可对接不同视图,同一控制器可处理多个相似视图的交互)。

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 的三大组件通过固定的流程协同工作,以 "用户添加数据" 为例,完整交互流程如下:

  1. 用户交互:用户在 View(如网页)中输入姓名和年龄,点击 "添加" 按钮;
  2. View 转发请求:View 捕获点击事件,将输入的参数(姓名、年龄)转发给 Controller;
  3. Controller 调度业务:Controller 接收请求,先做基础参数校验(如年龄是否为数字),再调用 Model 的addUser方法处理业务;
  4. Model 处理并通知:Model 执行addUser的业务逻辑(如合法性校验、存储数据),数据更新后通过 "观察者模式" 通知 View;
  5. View 更新界面:View 接收 Model 的通知,调用 Controller 获取最新数据,重新渲染用户列表,完成界面更新。

流程简化图: 用户操作 → View → Controller → Model(数据变化)→ View(界面更新)

4、优缺点

4.1 优点

  1. 职责清晰,解耦性强:数据(Model)、界面(View)、逻辑(Controller)分离,便于单独维护和修改;
  2. 可扩展性高:新增功能时,可独立扩展某一组件(如新增 "用户详情 View",无需修改 Model 和 Controller 核心逻辑);
  3. 可测试性强:Model 可独立单元测试,View 可通过模拟数据测试渲染,Controller 可模拟交互测试逻辑;
  4. 复用性好:同一 Model 可对接多个 View(如 "用户数据" 可同时在 "列表 View" 和 "详情 View" 中展示),同一 Controller 可处理多个相似 View 的交互。

4.2 缺点

  1. 结构复杂,学习成本高:对于简单应用(如静态网页),MVC 的三层结构会增加代码冗余和开发成本;
  2. Controller 可能过度臃肿:在复杂应用中,Controller 需协调大量 Model 和 View,容易成为 "万能组件",导致逻辑冗余;
  3. View 与 Model 的间接依赖:部分实现中,View 仍需了解 Model 的数据结构(如渲染时需知道用户的nameage字段),未完全解耦;
  4. 不适合小型应用:小型项目(如工具类 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层提供的数据实现动态更新。

  1. 展示用户界面(如按钮、列表、表单);
  2. 接收用户交互(如点击、输入、滑动);
  3. 不包含业务逻辑,仅负责 "视图渲染" 和 "交互转发"。

2.2 Model:数据访问层

以数据为中心,不直接与用户界面交互。负责数据结构定义,数据管理(获取、存储、更新等),以及业务逻辑处理。

  1. 存储应用的核心数据(如用户信息、商品列表);
  2. 封装数据逻辑(如数据请求、本地存储、数据验证);
  3. 不依赖任何其他组件,仅关注 "数据本身"。

2.3 ViewModel:表示逻辑层

作为连接Model和View的桥梁,通常一个View对应一个ViewModel。View和

作为 View 与 Model 的 "中间层",隔离视图与数据; 2. 封装视图相关的业务逻辑(如 "点击按钮后请求数据""输入框内容验证"); 3. 维护 "视图状态"(如 isLoadingisShowModal),暴露给 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

4.2 设计技巧

Model层

  • model层存放本应用核心数据结构,这层本身和UI开发关系不大,让用户按照自己的业务逻辑进行封装。

ViewModel层

注意:

ViewModel层不只是存放数据,它同时需要提供数据的服务及处理。

  • ViewModel层是为视图服务的数据层。其设计具有两个特点:
    • 按照页面组织数据。
    • 每个页面数据进行懒加载。

View层

View层根据需要来组织,但View层需要区分一下三种组件:

  • 页面组件:提供整体页面布局,实现多页面之间的跳转,前后台事件处理等页面内容。
  • 业务组件:被页面引用,构建出页面。
  • 共享组件:与项目无关的多项目共享组件。

共享组件和业务组件的区别:

业务组件包含了ViewModel数据,没有ViewModel,这个组件不能运行。

共享组件:不包含ViewModel层的数据,需要的数据从外部传入。共享组件包含一个自定义组件,只要外部参数(无业务参数)满足,就可以工作。

三、三层架构

鸿蒙(HarmonyOS)的三层架构是针对 模块化、可复用、可定制 的应用开发需求设计的分层模型,核心目标是解耦代码、提升复用效率、适配多设备形态(如手机、平板、手表、车机等)。其架构设计遵循 "高内聚、低耦合" 原则,通过明确的分层职责和依赖关系,支持大型应用的协同开发与灵活部署。

1、三层架构核心概念与设计理念

鸿蒙三层架构从下到上分为 commons(公共能力层)、features(基础特性层)、products(产品定制层),每层职责边界清晰,依赖关系严格单向(不允许反向依赖):

  1. 复用性优先:将全应用通用的能力(如工具类、配置)抽离到最底层,供上层任意复用,减少重复开发。
  2. 特性模块化:将应用的独立功能(如 "用户登录""商品列表")封装为可独立编译、可定制的特性模块,支持按需集成。
  3. 多设备适配:顶层针对不同设备形态(如手机、手表)定制产品包,底层能力与特性模块无需修改即可跨设备复用,降低多端开发成本。
  4. 依赖可控:严格限制依赖方向(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 层不能依赖 featuresproducts 层(避免耦合业务逻辑,确保通用性)。

2.2 features(基础特性层):中间层的 "功能模块化单元"

核心定位

应用的 业务特性集合,每个 feature 对应一个相对独立的功能模块(如 "首页轮播""购物车""个人中心"),具备完整的 "UI + 业务逻辑",可独立开发、编译、测试。

主要内容
  • 业务特性模块:每个模块高内聚(包含该功能所需的所有代码)、低耦合(与其他模块通过接口交互,不直接依赖内部实现)。例如:
    • "登录模块":包含登录页面 UI、登录接口调用、验证码逻辑、登录状态管理。
    • "商品列表模块":包含列表 UI、下拉刷新 / 上拉加载、商品筛选逻辑、商品数据模型(业务专属字段)。
  • 特性间交互接口:若多个 feature 需交互(如 "购物车" 需调用 "用户登录" 的状态),通过定义 接口(interface) 实现,避免直接依赖模块内部代码(如 "登录模块" 暴露 "获取登录状态" 接口,"购物车" 通过接口调用,不依赖 "登录模块" 的具体实现)。
编译部署

根据是否需要 "独立部署",分为两种形态:

  • 非独立部署的 feature:编译为 HAR/HSP 包,作为 "组件" 被其他模块(如其他 featureproducts 层)依赖。例如 "通用弹窗提示" 特性,无独立入口,仅作为功能组件被调用。
  • 独立部署的 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 层是最顶层,featurescommons 层不能依赖它(确保下层模块的通用性)。

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)文件中配置依赖

JSON 复制代码
{
  "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"
  }
}
// 其他同理
相关推荐
caoerzhong27 分钟前
JeeWMS 开源仓库管理系统多租户架构解析:一套 Java WMS 如何同时服务多个货主与多个仓库
java·架构·开源·vue
聚搜云——JuSouClouD44 分钟前
阿里云代理商能帮忙设计架构方案吗?有哪些增值服务
阿里云·架构·云计算
周胡杰1 小时前
将现有 Compose Multiplatform 业务接入 HarmonyOS:架构、适配与持续同步
harmonyos·鸿蒙·cmp
白远山1 小时前
智慧场馆解决方案软件开发实战:从架构设计到落地部署指南
java·开发语言·架构·需求分析
m0_587383002 小时前
折扣卡CPS软件开发实战:从系统架构设计到上线指南
java·小程序·架构·需求分析
Dawson Zhu2 小时前
基于 OKF 知识图谱的 Text2SQL 领域知识注入实践——半导体晶圆厂数据资产知识库 MVP 剖析
人工智能·语言模型·架构·aigc·agi
晚安日记wanna2 小时前
批量请求失败只弹一个 Toast面试官想听五层
前端·面试·架构
大模型码小白2 小时前
告别造假数据,直接连数据库查真实时序数据喂给 TimechoAI 大模型
java·数据库·人工智能·microsoft·架构
晚安日记wanna2 小时前
大表 DDL 面试翻车现场Online DDL 为什么还会锁死业务
数据库·面试·架构
晚安日记wanna2 小时前
MySQL 主从延迟别只答并行复制
数据库·面试·架构