本文基于 HarmonyOS 5.x + ArkTS + Stage模型,结合企业级商城、IM、金融、物联网等项目实战,详细讲解鸿蒙应用模块化设计思想。

第一章 为什么企业级HarmonyOS项目一定要模块化

一、什么是模块化(Modularization)

很多刚接触 HarmonyOS 的同学都会有一个误区:

把代码放到不同文件夹就是模块化。

实际上,并不是。

例如下面这种结构:


entry
 ├── pages
 ├── login
 ├── order
 ├── mine
 ├── cart
 ├── network
 ├── utils
 └── model

虽然目录很多,但它们仍然属于 同一个 Module

整个应用最终仍然会编译成:


Entry HAP

也就是说:

整个项目:

  • 一个编译单元
  • 一个依赖关系
  • 一个生命周期
  • 一个安装包

这并不能称之为真正的模块化。


什么才是真正的模块化?

真正的模块化,是把系统拆分成多个独立的模块(Module)。

例如:


App

├── entry
│
├── feature_login
│
├── feature_order
│
├── feature_cart
│
├── feature_mine
│
├── feature_home
│
├── feature_message
│
├── feature_pay
│
├── common_ui
│
├── common_network
│
├── common_router
│
├── common_database
│
├── common_account
│
├── common_permission
│
└── common_utils

每个模块:

  • 独立开发
  • 独立维护
  • 独立编译
  • 独立测试
  • 可重复利用

最终共同组成整个 App。

这才是真正意义上的模块化。


二、为什么需要模块化?

假设现在开发一个商城 App。

项目刚开始的时候:


首页

登录

我的

整个项目可能只有:


10000 行代码

一个 Module 完全没有问题。

但是一年以后……

增加了:


订单

购物车

支付

直播

优惠券

搜索

消息

客服

定位

积分

会员

活动

秒杀

物流

发票

钱包

项目已经变成:


40 万行代码

继续开发:


80 万行

再继续:


120 万行

很多互联网公司的 HarmonyOS 项目:


200 万+

300 万+

500 万+

如果仍然只有一个 Module,会发生什么?


三、单 Module 项目的问题

问题一:编译越来越慢

例如:


entry

里面放了:


全部页面

全部组件

全部资源

全部网络

全部数据库

全部业务

任何地方修改了一行代码:


Text("Hello")

整个 Module 都需要重新参与编译。

例如:


修改首页按钮颜色

↓

重新编译整个项目

↓

等待几十秒甚至几分钟

项目越大:

编译速度越慢。

很多大型项目:


Clean Project

需要

5~10 分钟

对于开发效率来说,这是非常致命的。


问题二:多人开发冲突严重

假设:

团队有:


20 人

所有人都开发:


entry

Git 冲突会越来越严重。

例如:

A 修改:


routes.json

B 修改:


routes.json

C 修改:


routes.json

每天:


Git Merge

都会冲突。

尤其:


module.json5

build-profile.json5

oh-package.json5

这些公共配置文件。

几乎天天冲突。


问题三:代码耦合越来越严重

例如:

登录模块:


直接引用

订单页面

订单模块:


又引用

购物车

购物车:


又引用

首页

首页:


又引用

登录

形成:


Login

↓

Order

↓

Cart

↓

Home

↓

Login

这就是:

循环依赖(Circular Dependency)

后果:


编译异常

依赖混乱

维护困难

甚至出现:


无法打包

问题四:业务边界越来越模糊

例如:

登录相关代码:


login

↓

utils

↓

network

↓

pages

↓

common

↓

model

到处都是。

新人来了以后:

根本不知道:

登录代码到底在哪里。

通常会问:


登录接口在哪?

登录页面在哪?

登录缓存在哪?

登录 Token 在哪?

登录状态在哪?

找半天。


问题五:重复代码越来越多

例如:

订单模块:

自己写:


LoadingDialog

首页:

又写一个:


LoadingDialog

购物车:

再写一个:


LoadingDialog

消息模块:

继续写:


LoadingDialog

最后:

整个项目:


20 个 Loading

功能一样。

代码不同。

维护十分痛苦。


问题六:资源越来越混乱

例如:

图片:


icon_back.png

结果:

首页:


一个

订单:


一个

购物车:


一个

支付:


一个

实际上:

完全一样。

最后:

安装包越来越大。


问题七:启动越来越慢

例如:

首页其实只需要:


首页

登录

网络

但是由于:

所有代码:

全部打包进:


Entry

启动时:

所有初始化:


数据库

推送

地图

IM

支付

定位

蓝牙

AI

全部执行。

启动时间越来越长。


四、模块化能够解决什么?

模块化最大的目标只有一句话:

高内聚,低耦合。

什么意思?

例如:

登录模块:


feature_login

里面只有:


登录页面

登录接口

Token

用户信息

验证码

密码登录

短信登录

不会引用:


购物车

订单

支付

订单模块:


feature_order

里面:

只有:


订单

退款

售后

评价

这就是:

高内聚。

不同模块之间:

通过接口通信。

而不是:

直接引用页面。

这就是:

低耦合。


五、模块化带来的收益

真正落地模块化以后,一个大型 HarmonyOS 项目通常会得到以下收益:

收益 说明
编译更快 修改局部模块即可重新编译
开发效率更高 各团队独立开发,互不影响
Git 冲突减少 每个团队维护自己的模块
代码职责清晰 模块边界明确,易于维护
更容易测试 单模块可独立调试、单元测试
更容易复用 公共能力可沉淀为 HAR/HSP
安装包优化 支持按需加载,减少初始包体积
更利于持续迭代 新业务可新增模块,不影响现有功能

六、模块化不是拆得越细越好

很多团队一开始会陷入另一个误区:


Button

↓

一个 Module

Text

↓

一个 Module

Image

↓

一个 Module

结果:

项目变成:


80 多个 Module

依赖关系复杂到无法维护。

因此:

模块化的目标不是“越多越好”,而是“职责清晰、粒度合理”。

通常建议:

  • 按业务拆分:登录、订单、支付、消息等。
  • 按公共能力拆分:网络、数据库、工具、公共 UI。
  • 避免为了拆分而拆分,否则维护成本会高于收益。

本章小结

本章主要介绍了 HarmonyOS 模块化的必要性,以及单 Module 项目在企业开发中的常见问题。理解这些背景后,后续学习 HAR、HSP、Feature HAP、Entry HAP 等模块类型,以及企业级模块架构设计会更加容易。

第二章 HarmonyOS 四种模块(Entry、Feature、HAR、HSP)深度解析

上一章,我们介绍了为什么企业项目一定要做模块化。

但是很多开发者真正开始拆分项目时,又会遇到新的问题:

HarmonyOS 为什么有四种 Module?

例如:


Entry HAP

Feature HAP

HAR

HSP

很多人刚开始学习的时候,经常分不清:

  • HAR 和 HSP 有什么区别?
  • 为什么官方现在推荐 HSP?
  • Feature 为什么还能独立安装?
  • 公共代码到底应该放 HAR 还是 HSP?
  • 企业项目到底如何选择?

这一章,我们就彻底讲透 HarmonyOS 四种模块。


一、HarmonyOS 的模块组成

一个完整的 HarmonyOS 应用,并不是只有一个 Module。

官方推荐采用:


App
│
├── Entry HAP
│
├── Feature HAP
│
├── HAR
│
└── HSP

可以把它理解成一个大型建筑:


整个App

↓

一栋写字楼

里面包含很多楼层。

例如:


Entry

↓

大厅

Feature

↓

各个办公区

HAR

↓

公共工具室

HSP

↓

共享会议室

每一种 Module 都承担不同职责。


二、什么是 HAP?

很多新人第一眼看到:


Entry HAP

就会问:

HAP 是什么?

其实:

HarmonyOS 的安装包就是:


HAP

类似于 Android:


APK

或者:

iOS:


IPA

因此:


Entry

↓

最终生成

↓

Entry.hap

Feature:


Feature

↓

Feature.hap

都属于:


Harmony Ability Package

即:

HarmonyOS Ability 安装包。


三、Entry HAP

Entry 是整个 App 的入口模块。

例如:


entry

通常里面包括:


App启动

Ability

首页

Navigation

初始化SDK

启动配置

项目结构:


entry
│
├── src
│
├── App.ets
│
├── EntryAbility
│
├── resources
│
└── module.json5

整个应用:

安装后:

首先启动:


Entry Ability

因此:

Entry:

一定存在。

一个应用:

通常:


只有一个 Entry

Entry 的职责

Entry 不应该写大量业务。

它应该负责:


App启动

初始化

首页

路由入口

Ability

启动页

全局配置

例如:


AppStorage.setOrCreate("token", "")

例如:

初始化:


Logger.init()

Router.init()

Network.init()

Database.init()

这些都适合放 Entry。

但是:

不要把:


订单

支付

聊天

商城

直播

全部放进去。

否则:

Entry 会越来越庞大。


四、Feature HAP

Feature:

就是:

业务模块。

例如:

商城:


feature_home

订单:


feature_order

支付:


feature_pay

聊天:


feature_chat

个人中心:


feature_mine

整个项目:

可能变成:


App

│
├── entry
│
├── feature_home
│
├── feature_order
│
├── feature_pay
│
├── feature_message
│
└── feature_mine

是不是业务边界一下子清晰了?


五、Feature 的优点

例如:

订单团队:

只维护:


feature_order

聊天团队:

维护:


feature_chat

首页团队:

维护:


feature_home

互不影响。

Git:

冲突明显减少。


Feature 可以独立编译

例如:

修改:


feature_order

理论上:

只需要重新编译:


feature_order

而不是:

整个工程。

对于大型项目:

开发效率会提升很多。


Feature 可以按需安装

HarmonyOS 一个非常大的优势就是:

Feature 支持:

按需安装(On Demand Install)。

例如:

用户第一次安装:

只安装:


Entry

Home

Mine

支付:

暂时不安装。

直播:

暂时不安装。

AI:

暂时不安装。

直到:

用户点击:


直播

系统:

再下载:


feature_live.hap

这样:

首包:

就可以非常小。


六、HAR(Harmony Archive)

很多人第一次看到:


HAR

以为:

也是一个 App。

其实不是。

HAR:

不能安装。

不能运行。

不能启动。

它只是:

一个代码库。

例如:


common_utils

里面:


DateUtil

StringUtil

FileUtil

ToastUtil

SPUtil

最终:

编译成:


common_utils.har

其它 Module:

依赖:


common_utils.har

即可。


HAR 的特点

HAR:

最大的特点:


不能独立安装

例如:


common_network.har

里面:


HttpClient

Request

Response

Interceptor

不会:

生成:


HAP

而是:

被:


Entry

Feature

引用。

编译时:

代码:

直接:

复制进去。

因此:

HAR:

类似:

Android:


AAR

或者:

Java:


Jar

七、HAR 的优缺点

优点:


简单

方便

依赖少

容易开发

但是:

它也有一个最大的问题:

代码会复制。

例如:


Entry

↓

引用

common.har

订单:


Order

↓

引用

common.har

支付:


Pay

↓

引用

common.har

最终:

编译后:


Entry

包含 common

Order

也包含 common

Pay

再次包含 common

也就是说:

同一份代码:

可能:

出现:

很多次。

对于大型项目:

包体积:

会越来越大。


八、HSP(Harmony Shared Package)

HSP:

官方近几年重点推荐的共享模块方案。

可以理解为:

真正的共享运行时模块。

例如:


common_network

整个 App:

只有:


一个

实例。

所有 Feature:

共同使用。

而不是:

复制很多份。

例如:


Feature_A

↓

HSP

Feature_B

↓

HSP

Feature_C

↓

HSP

大家:

共享:

同一份:

代码。

因此:

安装包:

明显变小。


九、HAR 与 HSP 的本质区别

下面这张表,是面试中最常见的问题之一:

对比项 HAR HSP
是否可独立安装 ✅(作为共享包随应用分发)
是否可运行
是否支持共享 编译时复制 运行时共享
是否会重复打包 不会
是否支持按需加载
推荐场景 小型公共库 企业级公共能力

一句话总结:

  • HAR:编译时共享,代码会复制到依赖它的模块中。
  • HSP:运行时共享,一份代码供多个模块共同使用,更适合大型项目。

十、企业项目如何选择?

一般建议如下:

Entry

负责:


App启动

Ability

Navigation

初始化

Feature

负责:


登录

首页

订单

支付

聊天

个人中心

HAR

适合:


工具类

字符串处理

日期工具

日志工具

简单UI组件

HSP

适合:


网络

数据库

账号体系

IM

公共SDK

权限管理

Router

公共业务能力

这些模块通常会被多个 Feature 同时依赖,采用 HSP 能避免重复打包,提高运行效率。


十一、一个企业级项目的模块示例


App
│
├── entry                  // 应用入口
│
├── feature_home           // 首页
├── feature_login          // 登录
├── feature_order          // 订单
├── feature_cart           // 购物车
├── feature_pay            // 支付
├── feature_message        // 消息
├── feature_mine           // 我的
│
├── common_ui              // UI组件(HAR)
├── common_utils           // 工具(HAR)
│
├── core_network           // 网络(HSP)
├── core_database          // 数据库(HSP)
├── core_account           // 用户(HSP)
├── core_router            // 路由(HSP)
├── core_permission        // 权限(HSP)
└── core_base              // 基础能力(HSP)

这种结构具有以下特点:

  • 业务模块职责单一,便于团队协作。
  • 公共能力统一维护,避免重复实现。
  • 后续新增业务(如直播、AI、会员)时,只需新增对应 Feature,不影响已有模块。

本章小结

本章重点介绍了 HarmonyOS 四种模块类型及其定位:

  • Entry HAP:应用入口,负责启动和全局初始化。
  • Feature HAP:承载具体业务功能,可按需安装。
  • HAR:静态共享代码库,适合工具和简单公共组件。
  • HSP:运行时共享包,适合网络、数据库、账号等核心公共能力,是企业级项目的推荐方案。

第三章 企业级模块划分原则(按业务、按能力、按层次)


上一章,我们已经了解了:

  • Entry
  • Feature
  • HAR
  • HSP

很多同学觉得:

"我已经知道四种 Module 了,现在是不是直接拆模块就行?"

实际上,真正困难的并不是创建 Module

而是:

如何划分 Module。

很多公司的项目:

Module越来越多,

最后却越来越乱。

例如:


common

common2

common3

base

base2

utils

utils2

sdk

core

business

manager

module

半年以后……

连项目负责人都不知道:

某个工具类到底放哪里。

所以,

企业真正需要的是:

模块划分原则(Module Design Principle)

这一章,我们从大型互联网项目出发,讲透HarmonyOS模块拆分思想。


一、模块不是拆得越多越好

很多新人最容易犯的错误:

看到官方推荐模块化,

于是开始疯狂创建Module。

例如:


Button

↓

button_module

Text:


text_module

Image:


image_module

Toast:


toast_module

Dialog:


dialog_module

最后:

整个项目:


90+
Module

结果:

依赖关系变成:


Button

↓

Toast

↓

Utils

↓

Base

↓

Common

↓

Network

↓

Button

形成:

循环依赖。

整个项目:

没人敢动。


为什么不能拆太细?

因为:

Module:

不是目录。

它具有:


独立编译

独立依赖

独立资源

独立生命周期

Module越多:

意味着:


更多依赖

更多配置

更多版本

更多维护成本

所以:

模块数量:

并不是越多越先进。

而是:

刚刚好。


二、企业为什么拆模块?

真正的大厂:

拆模块:

只有三个目的:


职责分离

代码复用

团队协作

除此之外:

不要拆。

例如:

商城:


首页

订单

购物车

支付

消息

个人中心

它们:

天然就是:

不同业务。

所以:

拆:


feature_home

feature_order

feature_cart

没有任何问题。

但是:

不要:


OrderList

↓

一个Module

OrderDetail:


一个Module

OrderRefund:


一个Module

这种拆法:

维护成本:

远远高于收益。


三、企业级模块划分三原则

真正的大型HarmonyOS项目,

通常遵循:

第一原则:按业务拆

这是:

最推荐的方式。

例如:


feature_login

负责:


登录

注册

验证码

找回密码

短信登录

全部:

属于:

登录业务。

不要:

把:

验证码:

放:


common

密码:

放:


utils

登录:

放:


pages

这样:

业务就散了。

应该:

全部:

放:


feature_login

这叫:

业务内聚。


再例如:

订单:


feature_order

里面:


订单列表

订单详情

退款

售后

评价

物流

订单支付

全部:

属于:

订单。

放一起。

新人:

一分钟:

就能找到。


第二原则:按能力拆

有一些东西:

并不是:

业务。

例如:

网络:


HttpClient

数据库:


Database

日志:


Logger

Toast:


Toast

Router:


Router

权限:


Permission

它们:

所有业务:

都会使用。

所以:

应该:

抽出来。

例如:


core_network

里面:


Request

Response

Interceptor

HttpClient

Retry

订单:

调用:


http.get()

首页:

调用:


http.get()

登录:

也是:


http.get()

大家:

共享。

这就是:

能力模块。


第三原则:按层次拆

企业项目:

一般:

至少:

四层。

例如:


UI

↓

业务

↓

数据

↓

基础能力

可以画成:


Feature

↓

Repository

↓

Network

↓

Database

所有:

Feature:

只能:

调用:

Repository。

Repository:

负责:

获取:

数据。

Repository:

调用:

Network。

Network:

调用:

Http。

这样:

职责:

非常清晰。


四、一个正确的企业模块结构

例如:

商城:


App

│
├── entry
│
├── feature_home
├── feature_login
├── feature_order
├── feature_cart
├── feature_message
├── feature_pay
├── feature_mine
│
├── core_network
├── core_database
├── core_router
├── core_account
├── core_permission
├── core_storage
│
├── common_ui
├── common_utils
├── common_widget
│
└── model

是不是:

职责:

已经非常清晰?


五、为什么很多公司都有 Base 模块?

很多HarmonyOS项目:

都会有:


base

很多新人:

不知道:

Base:

到底放什么?

其实:

Base:

不是:

工具类。

也不是:

公共组件。

Base:

应该放:

整个应用:

最基础的东西。

例如:


BaseAbility

BaseViewModel

BaseRepository

BasePage

BaseDialog

BaseConstants

BaseException

这些:

所有模块:

都会继承。

例如:


export class HomeViewModel extends BaseViewModel {

}

订单:

也是:


export class OrderViewModel extends BaseViewModel {

}

统一:

生命周期。

统一:

日志。

统一:

异常。

统一:

Loading。


六、为什么还有 Core?

很多项目:

又有:


core

Base:

和:

Core:

有什么区别?

很多人:

混了。

其实:

很好理解。

Base:

偏:

抽象。

例如:


BaseViewModel

Core:

偏:

能力。

例如:


core_network

提供:


HttpClient

Core:

不是:

父类。

而是:

能力。

例如:


core_database

里面:


Room

Preferences

KVStore

都是:

能力。


七、为什么还有 Common?

很多项目:

还有:


common

Common:

放什么?

一般:

放:

可以直接使用的:

公共资源。

例如:


Loading

Dialog

TitleBar

EmptyView

ErrorView

NoDataView

RefreshLayout

大家:

直接:

引用。

即可。


八、Feature 为什么不能互相引用?

例如:

订单:

引用:


feature_login

登录:

又引用:


feature_order

是不是:

很容易:

形成:


Order

↓

Login

↓

Order

循环依赖。

因此:

企业:

一般:

规定:


Feature

不能依赖

Feature

那怎么办?

抽:

公共模块。

例如:


UserRepository

放:


core_account

登录:

调用:


UserRepository.login()

订单:

调用:


UserRepository.getUser()

大家:

共同:

依赖:


core_account

而不是:

互相引用。


九、模块依赖应该像一棵树

企业:

推荐:

依赖:

单向。

例如:


                Entry
                  │
     ┌────────────┼────────────┐
     │            │            │
FeatureHome  FeatureOrder  FeatureMine
     │            │            │
     └────────────┼────────────┘
                  │
           Repository(HSP)
                  │
      ┌───────────┼────────────┐
      │           │            │
 Network(HSP) Database(HSP) Account(HSP)
      │
      │
 Utils(HAR)

注意:

所有箭头:

只有:

向下。

绝不能:

反向。


十、一个错误的依赖关系

例如:


FeatureHome

↓

FeatureOrder

↓

FeaturePay

↓

FeatureMine

↓

FeatureHome

最终:

形成:


Circle

编译:

越来越慢。

维护:

越来越困难。

所以:

企业:

一般:

使用:

单向依赖(One-way Dependency)


十一、模块划分的黄金法则

如果一个模块满足下面三个条件中的两个以上,就应该考虑拆分:

判断标准 是否建议拆分
功能可以独立开发
可以独立测试
可以独立发布或升级
被多个业务共同依赖
团队独立维护

反之,如果一个模块:

  • 只能被一个页面使用;
  • 没有复用价值;
  • 拆出来反而增加依赖;

那么通常没有必要单独建 Module


十二、企业项目模块命名规范

建议统一命名,避免出现 common2newCommon 这类难以维护的名称。


entry                  // 应用入口

feature_login          // 登录业务
feature_home           // 首页业务
feature_order          // 订单业务
feature_cart           // 购物车业务
feature_pay            // 支付业务
feature_message        // 消息业务
feature_mine           // 我的业务

core_network           // 网络核心能力
core_database          // 数据库能力
core_account           // 账号能力
core_router            // 路由能力
core_permission        // 权限能力
core_storage           // 存储能力

common_ui              // 公共UI组件
common_utils           // 工具库
common_widget          // 通用业务组件

base                   // 基础抽象层

这样的命名,即使是新加入团队的开发者,也能快速理解整个工程结构。


本章总结

本章围绕 HarmonyOS 企业级模块划分原则 展开,重点掌握了:

  • 为什么模块不是越多越好;
  • 三大拆分原则:按业务、按能力、按层次
  • Base、Core、Common 的职责边界;
  • 为什么 Feature 不应直接依赖 Feature;
  • 如何设计单向依赖,避免循环引用;
  • 企业项目推荐的模块命名规范与目录结构。

这些原则不仅适用于 HarmonyOS,也适用于 Android、Flutter 等大型客户端项目。

第四章 HarmonyOS Module 创建与配置(Entry、Feature、HAR、HSP)实战


前面三章,我们已经理解了模块化设计思想。

但是很多开发者真正开始搭建项目时,又会遇到新的问题:

DevEco Studio 到底如何创建 Module?

例如:

  • Entry 怎么创建?
  • Feature 如何依赖 Entry?
  • HAR 怎么导出接口?
  • HSP 怎么共享?
  • module.json5 到底有什么作用?
  • build-profile.json5 怎么配置?
  • oh-package.json5 怎么管理依赖?

这一章,我们通过完整实战,把整个过程讲透。


一、HarmonyOS 工程结构

创建一个默认 HarmonyOS 工程后,大概如下:


Demo
│
├── AppScope
│
├── entry
│
│   ├── src
│   ├── resources
│   ├── module.json5
│   └── oh-package.json5
│
├── build-profile.json5
│
├── hvigorfile.ts
│
├── hvigor
│
└── oh-package.json5

很多新人第一眼看到:


AppScope

就蒙了。

实际上:

整个工程可以理解成三层:


工程(Project)

↓

Module

↓

Source

即:


Project
│
├── Entry Module
│
└── Feature Module

二、什么是 Project?

Project:

就是整个应用。

例如:


ShoppingMall

里面可以拥有:


Entry

Feature

HAR

HSP

所有 Module。

因此:

一个 Project:

可以包含:

几十个 Module。

例如:


Project

↓

35 Modules

企业项目:

十分常见。


三、Module 创建流程

在 DevEco Studio 中:

右键:


Project

选择:


New

↓

Module

随后会看到:


Entry

Feature

Static Library(HAR)

Shared Library(HSP)

不同版本 DevEco Studio 的名称可能略有差异,但核心类型保持一致。


四、创建 Entry

通常:

工程创建时:

已经自动生成:


entry

目录:


entry
│
├── src
│
├── resources
│
├── module.json5
│
├── oh-package.json5
│
└── build-profile.json5

一般:

不要删除。

整个App:

都会从这里启动。


五、创建 Feature

例如:

创建:


feature_order

目录:


feature_order
│
├── src
│
├── resources
│
├── module.json5
│
└── oh-package.json5

Feature:

里面:

可以写:


OrderPage

OrderDetail

OrderViewModel

OrderRepository

它:

就是:

订单业务。


一个业务一个 Feature

例如:


feature_login

负责:


登录

注册

验证码


feature_cart

负责:


购物车

商品结算


feature_message

负责:


聊天

通知

消息中心

这样:

职责:

十分清晰。


六、创建 HAR

选择:


Static Library

即可。

例如:


common_utils

生成:


common_utils
│
├── src
│
├── Index.ets
│
└── oh-package.json5

注意:

HAR:

没有:


Ability

没有:


pages

因为:

它不能运行。


七、HAR 为什么有 Index.ets?

例如:

里面:


// DateUtil.ets
export class DateUtil {

    static now(): string {
        return "2026"
    }

}

但是:

外部:

不能:

直接:

引用。

需要:

统一:

导出。

例如:


// Index.ets

export * from './src/main/ets/utils/DateUtil'

以后:

其它Module:

只需要:


import { DateUtil } from 'common_utils'

即可。

这就是:

统一出口。

也是:

企业:

推荐:

做法。


八、创建 HSP

选择:


Shared Library

例如:


core_network

生成:


core_network
│
├── src
│
├── Index.ets
│
├── module.json5
│
└── oh-package.json5

HSP:

和:

HAR:

目录:

几乎一样。

最大的区别:

不是:

目录。

而是:

编译方式。


九、Module 的配置文件

几乎:

每个Module:

都有:


module.json5

很多新人:

不知道:

它到底干嘛。

实际上:

它就是:

Module:

身份证。

例如:


{
  "module": {
    "name": "feature_order",
    "type": "feature",
    "mainElement": "EntryAbility",
    "deviceTypes": [
      "phone",
      "tablet"
    ]
  }
}

里面:

记录:


Module名称

类型

Ability

设备

权限

等等。


十、module.json5 常见字段

name


"name": "feature_order"

模块名称。

也是:

依赖名称。


type

例如:


"type":"entry"

或者:


"type":"feature"

决定:

当前:

Module:

类型。


mainElement

例如:


"mainElement":"EntryAbility"

指定:

启动Ability。

通常:

只有:

Entry:

需要。


deviceTypes

例如:


[
 "phone",
 "tablet"
]

表示:

当前模块:

支持:

哪些设备。

例如:

还能支持:


TV

Wearable

Car

十一、build-profile.json5

很多新人:

第一次:

看到:


build-profile.json5

以为:

只是:

Gradle。

其实:

不是。

它:

负责:

整个:

工程:

编译配置。

例如:


{
  "apiType":"stageMode"
}

还包括:


Signing

Product

BuildMode

Targets

等等。


十二、oh-package.json5

这是:

鸿蒙:

依赖管理文件。

类似:

Android:


build.gradle

或者:

Node:


package.json

例如:


{
  "dependencies": {
  }
}

所有:

第三方:

SDK:

都:

配置:

这里。

例如:


axios

crypto

二维码

图片库

等等。


十三、多 Module 如何依赖?

例如:

订单:

需要:

工具类。

首先:

common_utils:

导出:


export * from './DateUtil'

然后:

Order:

依赖:


{
 "dependencies": {
    "common_utils":"file:../common_utils"
 }
}

随后:

即可:


import { DateUtil } from 'common_utils'

是不是:

和:

npm:

很像?


十四、Feature 如何依赖 HSP?

例如:

网络:

放:


core_network

订单:

直接:

依赖:


{
 "dependencies": {
     "core_network":"file:../core_network"
 }
}

然后:


import { HttpClient } from 'core_network'

所有:

Feature:

都:

可以:

共享。


十五、一个企业项目依赖关系

例如:


                entry
                  │
        ┌─────────┴──────────┐
        │         │          │
 feature_home feature_order feature_mine
        │         │          │
        └─────────┼──────────┘
                  │
        core_network(HSP)
                  │
        core_database(HSP)
                  │
        common_utils(HAR)

这里:

要注意:

所有依赖:

都:

向下。

不要:

反向。


十六、统一导出 Index.ets

企业:

都会:

要求:

每个Module:

都有:


Index.ets

例如:


export * from './network/HttpClient'

export * from './network/Api'

export * from './network/Interceptor'

export * from './repository/UserRepository'

export * from './repository/OrderRepository'

以后:

外部:

只需要:


import {
    HttpClient,
    Api,
    UserRepository
} from 'core_network'

而不是:


import { HttpClient } from '../../../../../network'

这样:

路径:

不会:

越来越长。


十七、推荐目录结构

企业推荐每个 Module 保持统一目录风格,例如:


feature_order
│
├── src
│   └── main
│       ├── ets
│       │   ├── pages
│       │   ├── components
│       │   ├── viewmodel
│       │   ├── repository
│       │   ├── model
│       │   ├── service
│       │   ├── constants
│       │   └── utils
│       │
│       └── resources
│
├── Index.ets
├── module.json5
└── oh-package.json5

统一的目录规范可以让团队成员在不同业务模块之间快速切换,降低沟通成本。


十八、模块创建中的常见问题

1. 一个 Feature 可以直接引用另一个 Feature 吗?

不建议。

正确做法是:

  • 抽取公共能力到 HSP
  • 或抽取公共工具到 HAR
  • Feature 之间通过公共接口通信,而不是直接依赖。

2. HAR 可以包含页面吗?

可以包含页面代码,但 不能作为独立应用运行,通常不建议将完整业务页面放入 HAR。HAR 更适合作为工具库、UI 组件库等公共能力。


3. HSP 能否保存单例状态?

可以。由于 HSP 在运行时是共享的,非常适合维护全局账号信息、网络管理器、数据库连接等公共状态。但也要注意线程安全和生命周期管理。


本章总结

本章进入了 HarmonyOS 模块化的实战阶段,介绍了:

  • 如何创建 Entry、Feature、HAR、HSP;
  • module.json5build-profile.json5oh-package.json5 的作用;
  • Module 之间的依赖关系配置;
  • Index.ets 的统一导出规范;
  • 企业项目推荐的目录结构与实践建议。

掌握这些内容后,就可以真正开始搭建一个多 Module 的 HarmonyOS 工程。

第五章 企业级模块依赖设计(避免循环依赖)


在前面章节中,我们已经完成了:

  • 模块分类设计
  • Module 创建
  • HAR/HSP 使用方式
  • 基础目录规划

但是,当项目真正扩大以后,会遇到一个非常棘手的问题:

模块越来越多,依赖关系越来越复杂,最后出现循环依赖。

这是企业级 HarmonyOS 项目中最常见、也是最难解决的问题之一。


一、什么是模块依赖?

假设:

我们有:


feature_order

订单模块。

需要:


core_network

网络能力。

那么:

依赖关系:


feature_order

        ↓

core_network

表示:

订单模块:

可以使用:

网络模块。

代码:


import {
  HttpClient
} from "core_network"

这就是:

模块依赖。


二、什么是正确的依赖方向?

企业项目:

最核心原则:

高层业务依赖底层能力,底层不能反向依赖业务。

例如:

正确:


              Entry

                ↓

          Feature业务层

                ↓

        Repository数据层

                ↓

          Core能力层

                ↓

          Utils基础层

依赖方向:

永远:

向下。


三、错误的依赖设计

很多初学者会这样设计:

登录模块


feature_login

里面:


LoginPage

LoginViewModel

然后:

订单:

需要用户信息。

于是:

订单引用登录:


feature_order

        ↓

feature_login

看起来没问题。


但是:

登录退出时:

又需要通知订单刷新:

于是:

登录又引用订单:


feature_login

        ↓

feature_order

最终:

变成:


feature_login
        ↓
feature_order
        ↓
feature_login

形成:

循环依赖。


四、循环依赖有什么危害?

1. 编译失败

例如:


A

依赖

B


B

依赖

A

编译系统无法确定:

先编译谁。


2. 模块职责混乱

例如:

登录模块:

开始出现:


OrderList

OrderDetail

OrderRepository

订单模块:

出现:


LoginManager

UserLogin

最后:

没人知道:

代码应该放哪里。


3. 后期无法拆分

未来:

想把:

订单业务:

独立出去。

发现:

订单:

依赖登录。

登录:

依赖订单。

根本拆不出来。


五、如何解决循环依赖?

企业常用:

五种方式。


方案一:抽取公共能力模块

这是:

最常见方式。

错误:


订单

↓

登录

原因:

订单需要:

用户信息。

那么:

不要引用登录。

抽出来:


core_account

结构:


feature_login

        ↓

core_account


feature_order

        ↓

core_account

例如:

账号模块:


core_account

提供:


export class AccountManager {


    getUserInfo(){

    }


    getToken(){

    }


}

登录:

调用:


AccountManager.login()

订单:

调用:


AccountManager.getUserInfo()

两个业务:

互不依赖。


六、方案二:接口隔离

假设:

订单需要:

支付能力。

不要:

直接依赖:


feature_pay

例如:

错误:


import {
 PayPage
}
from "feature_pay"

因为:

业务模块耦合。


正确:

抽象接口:


core_payment

定义:


export interface PaymentService {


    pay(
      orderId:string
    ):Promise<boolean>


}

支付模块实现:


class WxPaymentService 
implements PaymentService {


}

订单:

只依赖:

接口。

不知道:

具体实现。


结构:


feature_order

        ↓

core_payment

        ↑

feature_pay

依赖:

变成:

单方向。


七、方案三:事件通信

很多时候:

两个业务:

只是需要:

通知。

例如:

登录成功:

通知首页刷新。

错误:

首页:

直接引用:

登录。


home

↓

login

正确:

使用:

EventHub。

例如:

登录:

发送:


eventHub.emit(
 "LOGIN_SUCCESS"
)

首页:

监听:


eventHub.on(
 "LOGIN_SUCCESS",
 ()=>{
    refresh()
 }
)

结构:

变成:


login

 ↓

EventCenter

 ↑

home

两个模块:

没有直接依赖。


八、方案四:Router解耦页面跳转

很多项目:

最大的问题:

就是:

页面跳转。

例如:

订单:

跳登录。

代码:


router.pushUrl({
 url:"LoginPage"
})

这样:

订单:

知道:

登录页面存在。

产生:

耦合。


正确:

统一:

Router模块。

例如:


core_router

定义:


Router.open(
 "login"
)

订单:

只知道:

路由名称。

不知道:

页面在哪里。


结构:


feature_order

        ↓

core_router

        ↑

feature_login

九、方案五:Repository层隔离

这是:

大型项目:

最常用架构。

例如:

订单页面:

不要:

直接访问:

网络。

错误:


OrderPage

↓

HttpClient

正确:

增加:

Repository:


OrderPage

↓

OrderRepository

↓

Network

结构:


feature_order

        ↓

repository

        ↓

core_network

例如:

页面:


orderRepository.getOrders()

Repository:

内部:


http.get("/orders")

页面:

完全不知道:

接口细节。


十、企业推荐依赖模型

大型 HarmonyOS 项目:

推荐:

下面结构:


                entry

                  ↓

        -------------------

        feature层

                  ↓

        -------------------

        repository层

                  ↓

        -------------------

        core能力层

                  ↓

        -------------------

        base/utils层

具体:


entry

 ↓

feature_login
feature_home
feature_order
feature_pay

 ↓

core_account
core_router
core_network
core_database

 ↓

common_utils
common_ui

 ↓

base

十一、哪些模块可以互相依赖?

整理一个规则:

模块 可以依赖
Entry Feature、Core、Common
Feature Core、Common、Base
Core Base、Common
Common Base
Base

重点:

Feature:

不要依赖:

Feature。


十二、企业项目依赖检查规则

可以制定:

代码规范:

例如:

禁止:


feature_x

↓

feature_y

禁止:


core

↓

feature

禁止:


utils

↓

network

因为:

工具层:

不应该知道:

业务。


十三、实际商城项目依赖示例

完整结构:


                         entry

                           |

        -----------------------------------

        |              |                 |

 feature_home   feature_order    feature_pay


        |              |                 |

        -----------------------------------

                           |

                 core_repository


                           |

        -----------------------------------

        |              |                 |

 core_network   core_database   core_account


                           |

                    common_utils

                           |

                         base

这个结构:

可以支持:

百万级代码规模。


十四、模块化设计口诀

企业开发中:

总结为:

业务向下依赖,基础禁止向上。

Feature不互相引用,公共能力统一沉淀。

页面不要调接口,Repository隔离业务。

模块之间少直接调用,多使用接口和事件。


十五、本章总结

本章重点:

1. 理解模块依赖

模块之间:

通过依赖关系:

连接。


2. 避免循环依赖

不要:

Feature依赖Feature。


3. 使用解耦方案

包括:

  • 公共能力抽取
  • 接口隔离
  • EventHub通信
  • Router跳转
  • Repository架构

4. 掌握企业依赖方向

最终目标:

形成:


业务层

↓

能力层

↓

基础层

单向依赖。

第六章 HarmonyOS 模块化架构中的 MVVM 设计


前面五章,我们已经完成了:

  • 为什么需要模块化;
  • Entry / Feature / HAR / HSP 的区别;
  • 企业模块拆分原则;
  • Module 依赖设计;
  • 如何避免循环依赖。

但是还有一个核心问题:

一个 Feature Module 内部,代码应该怎么组织?

例如:


feature_order

里面:

到底放:

  • 页面?
  • 网络请求?
  • 数据模型?
  • 状态管理?
  • 数据库?

如果没有规范,一个 Feature 很快又会变成:


feature_order

├── pages
├── api
├── utils
├── model
├── manager
├── service
├── network
├── database
└── xxx

最后:

模块化失败。

因此企业项目通常会在 Module 内部继续采用:

MVVM + Repository 分层架构


一、为什么模块化需要 MVVM?

模块化解决的是:

大模块之间的问题。

MVVM解决的是:

一个模块内部的问题。

两者关系:

如下:


App模块化

解决:

模块边界


MVVM

解决:

模块内部代码职责

例如:

整个App:


feature_order

负责订单。

但是内部:

需要:


订单页面

订单状态

订单数据

订单接口

订单缓存

这时候:

使用:

MVVM。


二、HarmonyOS MVVM整体结构

企业项目常见:

如下:


Feature

│

├── View

│

├── ViewModel

│

├── Repository

│

├── DataSource

│

└── Model

完整链路:


用户操作

↓

View

↓

ViewModel

↓

Repository

↓

Network / Database

↓

Server

三、View层设计

View:

就是:

ArkUI页面。

例如:

订单列表:


pages

OrderListPage.ets

负责:

显示UI。

例如:


@Component
export struct OrderListPage {


    build(){

        List(){

        }

    }

}

View:

只负责:

三个事情:


1. 展示数据

例如:


Text(
 this.vm.orderCount.toString()
)

2. 响应用户操作

例如:

点击:


Button("刷新")
.onClick(()=>{

 this.vm.refresh()

})

3. 页面布局

例如:


Column(){

 Text()

 List()

 Button()

}

View:

不要:

做:

网络请求。

错误:


.onClick(()=>{

 http.get()

})

为什么?

因为:

UI知道业务细节。

后期:

无法维护。


四、ViewModel层设计

ViewModel:

是:

View和业务之间的桥梁。

负责:

  • 状态管理;
  • 调用业务;
  • 处理页面逻辑。

例如:


export class OrderViewModel {


    orders:Order[]=[]


    async loadOrders(){

    }


}

页面:

只调用:


vm.loadOrders()

五、HarmonyOS状态管理结合ViewModel

HarmonyOS:

常用:

状态:

包括:


@State

@Observed

@ObjectLink

@Provide

@Consume

企业项目:

通常:

不会:

让页面承担全部状态。

例如:

错误:


@State orders=[]

全部写页面。

页面:

越来越大。


推荐:

ViewModel管理:


class OrderViewModel {


 @State
 orders=[]


}

页面:

绑定:


this.vm.orders

六、Repository层设计

Repository:

是:

MVVM核心。

它负责:

统一数据来源。

例如:

订单数据:

可能来自:

服务器:


HTTP

本地:


Database

缓存:


Preferences

页面:

不应该知道。


例如:

页面:

调用:


orderVM.loadOrders()

ViewModel:

调用:


repository.getOrders()

Repository:

决定:

去哪取。


结构:


OrderPage

↓

OrderViewModel

↓

OrderRepository

↓

----------------

HTTP

Database

Cache

----------------

七、为什么一定需要Repository?

假设:

没有Repository。

页面:

直接:

调用:

接口。

现在:

需求变化:

原来:


服务器获取订单

改成:


本地缓存优先

那么:

所有页面:

全部修改。

例如:

有:

20个订单页面。

需要:

修改:

20次。


有Repository:

只改:

一个地方:


OrderRepository

即可。


八、Feature内部推荐目录

例如:

订单模块:


feature_order

│

├── pages

│   ├── OrderListPage.ets
│   ├── OrderDetailPage.ets
│
├── components

│   ├── OrderItem.ets
│
├── viewmodel

│   └── OrderViewModel.ets
│
├── repository

│   └── OrderRepository.ets
│
├── model

│   ├── Order.ets
│   └── Product.ets
│
├── service

│   └── OrderService.ets
│
├── constants

│
└── Index.ets

九、Model应该放哪里?

这是很多项目争议点。

例如:

订单对象:


export class Order {


 id:string

 amount:number


}

应该放:

哪里?


情况1:业务私有Model

例如:

只有订单使用:


Order
Refund
Delivery

放:


feature_order/model

即可。


情况2:多个业务共享

例如:

用户:


User

订单:

需要:

用户。

支付:

需要:

用户。

那么:

不要放:

feature_login。

应该:

提升:


core_account/model

或者:


common_model

十、HSP中的MVVM

公共能力:

也可以采用类似结构。

例如:

账号中心:


core_account(HSP)

│

├── model

│   User

│

├── repository

│   AccountRepository

│

├── service

│   LoginService

│

└── AccountManager

所有业务:

共享:

这个能力。


十一、网络层如何配合MVVM?

推荐:

不要:

业务直接:

调用:

HttpClient。

错误:


OrderPage

↓

HttpClient

正确:


OrderPage

↓

OrderVM

↓

OrderRepository

↓

ApiService

↓

HttpClient

例如:

Network模块:


core_network

提供:


HttpClient.request()

业务:

不知道:

底层实现。


十二、完整企业级架构图

最终:

一个大型HarmonyOS项目:

可以这样:


                         Entry

                           |

        ---------------------------------

        Feature模块

        |          |          |

      Home      Order       Pay


        |          |          |

        ---------------------------------

                     Repository


                           |

        ---------------------------------

        Core HSP

 Network   Account   Database   Router


                           |

                  Common HAR


                           |

                         Base

十三、MVVM中的数据流

以订单刷新为例:

用户:

点击:

刷新按钮。

流程:


第一步

View:


Button()
.onClick(()=>{

 vm.refresh()

})

第二步

ViewModel:


async refresh(){

 this.orders =
 await repository.getOrders()

}

第三步

Repository:


getOrders(){

 return api.getOrders()

}

第四步

Network:


HttpClient.request()

第五步

服务器:

返回数据。


最终:

状态更新。

页面:

自动刷新。


十四、模块化 + MVVM 的优势

组合之后:

得到:

企业级架构:

业务隔离


订单不会污染登录

易测试

可以测试:


OrderRepository

OrderViewModel

不用启动页面。


易扩展

新增:

直播:

只增加:


feature_live

不用修改:

其它业务。


易维护

新人:

进入项目:

看到:


feature_xxx

core_xxx

common_xxx

马上理解。


十五、常见错误总结

错误1

View里面写网络:


http.get()

问题:

UI和数据耦合。


错误2

Feature直接调用Feature:


Order

↓

Login

问题:

循环依赖。


错误3

所有Model放Common:

结果:


common_model

越来越大。

应该:

业务私有归业务。

共享才提升。


错误4

Repository不存在。

结果:

业务代码:

直接操作:

网络、数据库。

后期:

无法维护。


本章总结

本章讲解了:

  • HarmonyOS模块化中的MVVM设计;
  • View、ViewModel、Repository职责;
  • Feature内部目录规范;
  • Model放置原则;
  • HSP如何承载公共业务能力;
  • 数据流完整过程。

最终形成:

Feature负责业务,View负责展示,ViewModel负责状态,Repository负责数据,Core负责能力。

这是目前大型HarmonyOS企业项目中最常见的架构模式。

第七章 企业级网络层设计(core_network HSP 实战)


在企业级 HarmonyOS 项目中,网络层(Network Layer)几乎是所有业务模块都会依赖的能力

例如:


首页
    │
订单
    │
支付
    │
登录
    │
消息
    │
个人中心

所有模块都会请求服务器。

因此,网络层绝不能写在某个 Feature 中。

例如下面这种设计:


feature_login

├── LoginPage
├── LoginApi
├── HttpClient
├── Interceptor
└── Request

看似没问题。

但是很快:

订单模块:


feature_order

也需要:


HttpClient

购物车:

也需要。

支付:

也需要。

最后:

整个项目:

出现:


HttpClient

HttpClient2

RequestUtil

NetManager

HttpHelper

甚至:

四五套网络框架。

这是企业开发最忌讳的问题。


一、为什么网络层必须独立?

因为:

它属于:

公共能力(Core Capability)

而不是:

业务。

例如:

网络:

可以服务:


登录

订单

支付

IM

直播

AI

商城

所以:

应该放:


core_network(HSP)

整个项目:

共享:

一份。


二、企业推荐网络模块结构

通常:

网络模块:

如下:


core_network

│

├── client

│   HttpClient.ets

│

├── api

│   UserApi.ets
│   OrderApi.ets
│   PayApi.ets

│

├── interceptor

│   AuthInterceptor.ets
│   LogInterceptor.ets
│   RetryInterceptor.ets

│

├── model

│   BaseResponse.ets

│

├── exception

│   ApiException.ets

│

├── config

│   NetworkConfig.ets

│

├── manager

│   TokenManager.ets

│

└── Index.ets

职责:

十分清晰。


三、网络层为什么采用 HSP?

很多同学会问:

为什么不用 HAR?

例如:


common_network.har

原因:

HAR:

编译:

复制。

例如:


feature_home

↓

common_network.har

订单:


feature_order

↓

common_network.har

支付:


feature_pay

↓

common_network.har

最终:

三个:

HttpClient。

三个:

Interceptor。

三个:

TokenManager。

浪费:

内存。


HSP:

则:

整个App:

只有:


HttpClient

一个实例。

例如:


FeatureHome

      │

FeatureOrder

      │

FeatureMine

      │

──────────────

core_network(HSP)

──────────────

大家:

共享。

这也是 HarmonyOS 官方推荐 HSP 承载公共能力的重要原因。


四、网络请求完整流程

企业:

推荐:

如下:


Page

↓

ViewModel

↓

Repository

↓

Api

↓

HttpClient

↓

Interceptor

↓

Server

整个:

调用链:

固定。

例如:

订单:

页面:


vm.loadOrders()

ViewModel:


repository.getOrders()

Repository:


orderApi.queryOrders()

Api:


httpClient.get()

Http:

发送请求。

页面:

完全不知道:

接口细节。


五、HttpClient 封装

整个项目:

建议:

只有:

一个:

HttpClient。

例如:


export class HttpClient {

  async get<T>(url: string): Promise<T> {
    // 发起 GET 请求
    throw new Error("TODO")
  }

  async post<T>(url: string, body: object): Promise<T> {
    // 发起 POST 请求
    throw new Error("TODO")
  }
}

注意:

业务:

不要:

直接:

创建:


new HttpClient()

推荐:

单例:


export const httpClient = new HttpClient()

整个App:

共享。


六、为什么不要直接写 URL?

很多新人:

喜欢:

这样:


http.get(
"/user/login"
)

订单:

又写:


http.get(
"/order/list"
)

支付:

继续:


http.post(
"/pay"
)

最后:

URL:

散落:

整个项目。

维护:

困难。


正确:

抽:

Api。

例如:


UserApi

里面:


export class UserApi {

 login(){

 }

 logout(){

 }

}

订单:


OrderApi

里面:


export class OrderApi {

 queryOrders(){

 }

 deleteOrder(){

 }

}

所有:

接口:

集中。


七、Repository 不直接拼 URL

错误:


class OrderRepository{

 getOrders(){

   return http.get(
      "/order/list"
   )

 }

}

Repository:

知道:

URL。

以后:

接口:

改了。

所有:

Repository:

修改。


正确:

Repository:

调用:

Api。

例如:


class OrderRepository{

 getOrders(){

   return orderApi.queryOrders()

 }

}

URL:

全部:

放:

Api。


八、请求拦截器设计

企业:

都会:

有:

拦截器。

例如:

登录:

需要:

Token。

不要:

每次:

手写:


headers:{
 token:token
}

正确:

统一:

拦截。

例如:


AuthInterceptor

负责:

自动:

添加:


Authorization

Token

Language

Version

DeviceId

所有:

请求:

统一。


九、日志拦截器

开发阶段:

需要:

打印:

接口。

例如:


Request URL

Method

Headers

Body

响应:


Status

Data

Time

Size

所以:

增加:


LogInterceptor

以后:

关闭:

日志:

只修改:

一个地方。


十、Token 自动刷新

企业:

登录:

都会:

过期。

例如:

服务器:

返回:


401

不要:

页面:

自己:

处理。

正确:

放:


AuthInterceptor

流程:


Request

↓

401

↓

RefreshToken

↓

重新请求

↓

返回成功

整个:

业务:

完全:

不知道。


十一、多环境配置

企业:

至少:

三个环境。


开发

测试

正式

不要:

写:


const BASE_URL =
"https://api.xxx.com"

推荐:


NetworkConfig

例如:


export class NetworkConfig{

 static baseUrl:string=""

}

开发:

初始化:


https://dev.xxx.com

测试:


https://test.xxx.com

正式:


https://api.xxx.com

只修改:

配置。


十二、统一返回模型

不要:

接口:

返回:

各种:

类型。

推荐:

统一:


BaseResponse<T>

例如:


export class BaseResponse<T>{

 code:number

 message:string

 data:T

}

订单:

返回:


BaseResponse<Order[]>

登录:

返回:


BaseResponse<User>

统一:

解析。


十三、异常统一处理

不要:

每个页面:


try{

}catch{}

推荐:

网络层:

统一:

抛:


ApiException

例如:


Token失效

网络错误

超时

服务器错误

解析错误

ViewModel:

只处理:

业务。


十四、完整网络调用流程

以订单列表为例:


OrderPage
      │
      ▼
OrderViewModel
      │
      ▼
OrderRepository
      │
      ▼
OrderApi
      │
      ▼
HttpClient
      │
      ▼
AuthInterceptor
      │
      ▼
LogInterceptor
      │
      ▼
Server
      │
      ▼
BaseResponse<Order[]>
      │
      ▼
Repository
      │
      ▼
ViewModel
      │
      ▼
Page 自动刷新 UI

可以看到:

页面从始至终都不知道 URL、Token、Header、重试逻辑、异常处理。

这就是分层设计的价值。


十五、企业级 core_network 推荐目录


core_network
│
├── api
│   ├── UserApi.ets
│   ├── OrderApi.ets
│   ├── ProductApi.ets
│   ├── CartApi.ets
│   └── PayApi.ets
│
├── client
│   ├── HttpClient.ets
│   └── RequestBuilder.ets
│
├── interceptor
│   ├── AuthInterceptor.ets
│   ├── LogInterceptor.ets
│   ├── RetryInterceptor.ets
│   └── CacheInterceptor.ets
│
├── config
│   ├── NetworkConfig.ets
│   └── Environment.ets
│
├── manager
│   └── TokenManager.ets
│
├── model
│   ├── BaseResponse.ets
│   └── ApiResult.ets
│
├── exception
│   ├── ApiException.ets
│   └── ErrorCode.ets
│
├── utils
│   └── UrlUtil.ets
│
└── Index.ets

这样的结构可以支撑几十个业务模块共享同一套网络能力。


十六、本章总结

本章重点讲解了 HarmonyOS 模块化中的网络层设计

  • 为什么网络层应该放在 core_network(HSP)
  • 为什么不建议放在 Feature 或 HAR;
  • HttpClient、Api、Repository 的职责划分;
  • 拦截器(认证、日志、重试)的设计;
  • Token 自动刷新、多环境切换、统一返回模型;
  • 企业级网络模块推荐目录。

核心原则可以总结为一句话:

网络层只负责通信,Repository 负责业务数据,ViewModel 负责页面状态,View 只负责展示。

这样不仅能保证代码职责清晰,也便于团队协作和后续扩展。

第八章 企业级 Repository 设计(Repository 模式深度解析)


前面我们已经完成了网络层(core_network)的设计。

很多开发者会产生一个疑问:

既然已经有 HttpClient 了,为什么还需要 Repository?

例如:

下面这种代码很多项目都有:


Button("加载订单")
.onClick(async () => {
    const result = await httpClient.get("/order/list")
    this.orders = result.data
})

代码看起来很简单。

为什么企业项目却很少这样写?

因为:

随着业务越来越复杂,这种写法很快就会失控。


一、什么是 Repository?

Repository(仓库)可以理解为:

数据统一管理中心(Data Repository)

它最大的职责就是:

向上提供统一的数据接口,向下屏蔽数据来源。

例如:

订单列表:

页面只需要:


repository.getOrderList()

至于:

数据来自:


网络

数据库

缓存

本地文件

云端同步

页面:

完全不知道。


Repository 在整个架构中的位置

企业项目通常如下:


UI(Page)

     │

ViewModel

     │

Repository

     │

──────────────

Network

Database

Cache

File

──────────────

Repository:

就是:

所有数据来源的统一入口。


二、没有 Repository 会怎样?

例如:

订单页面:


@Component
export struct OrderPage {

    async aboutToAppear(){

        const data = await httpClient.get()

    }

}

第二个页面:


OrderDetailPage

又写:


httpClient.get()

第三个页面:

退款:

继续:


httpClient.get()

整个项目:

几十个页面:

全部:

直接访问:

Http。

问题:

越来越多。


问题一:重复代码

例如:

每个页面:

都有:


try{

}catch{}

都有:


Loading.show()

都有:


Toast.show()

都有:


response.code==200

几十个页面:

重复。


问题二:缓存难以统一

现在:

需求:

新增:

先读取本地缓存,再请求网络。

如果:

页面:

直接:

调用:

Http。

那么:

所有页面:

全部修改。

例如:

50个页面。

修改:

50次。


问题三:数据库同步困难

例如:

订单:

服务器返回。

需要:

保存:

数据库。

没有Repository。

所有页面:

自己:

写:


db.insert()

项目:

越来越乱。


三、Repository 最大价值

Repository:

负责:

统一:

数据来源。

例如:

页面:

调用:


repository.getOrders()

Repository:

内部:

可以:

这样:


数据库

↓

没有

↓

请求网络

↓

保存数据库

↓

返回数据

页面:

不知道。


以后:

如果:

需求:

改成:


缓存优先

Repository:

改。

页面:

一行:

不用动。


四、企业 Repository 目录

例如:

订单:


feature_order

│

├── repository

│      OrderRepository.ets

│

├── datasource

│      RemoteDataSource.ets

│      LocalDataSource.ets

│

├── model

│

└── pages

是不是:

比:

全部:

放:

Repository:

更清晰?


五、Repository 与 DataSource

很多互联网公司:

Repository:

下面:

还会:

继续:

拆:

DataSource。

为什么?

例如:

订单:

来源:

有:


HTTP

Database

Cache

如果:

全部:

写:

OrderRepository。

以后:

Repository:

超过:

3000行。

所以:

继续:

拆。


RemoteDataSource

负责:

服务器。

例如:


class RemoteDataSource{

    getOrders(){

    }

}

里面:

全部:

网络。


LocalDataSource

负责:

数据库。

例如:


class LocalDataSource{

    queryOrders(){

    }

}

里面:

全部:

数据库。


Repository:

只负责:

协调。

例如:


Repository

↓

Remote

↓

Local

六、Repository 工作流程

企业:

推荐:

如下:


Page

↓

ViewModel

↓

Repository

↓

LocalDataSource

↓

没有数据

↓

RemoteDataSource

↓

保存数据库

↓

返回ViewModel

↓

刷新UI

整个:

流程:

固定。


七、Repository 示例

例如:

订单:


export class OrderRepository {

    async getOrderList() {

        // 1、先查询数据库

        // 2、没有再请求服务器

        // 3、保存数据库

        // 4、返回结果

    }

}

页面:

永远:

只有:


vm.loadOrders()

八、Repository 为什么不能放 Network?

很多新人:

喜欢:

这样:


core_network

↓

UserRepository

↓

OrderRepository

这是:

错误。

为什么?

Repository:

属于:

业务。

不是:

网络。

例如:

订单:

Repository:

应该:

放:


feature_order

登录:

Repository:

放:


feature_login

网络:

只负责:

请求。


九、多个 Repository 如何协同?

例如:

首页:

需要:


商品

用户

广告

优惠券

是不是:

一个:

Repository?

不是。

企业:

一般:

多个:

Repository。

例如:


HomeRepository

UserRepository

BannerRepository

CouponRepository

ViewModel:

组合:

调用。

不要:

一个:

万能Repository。


十、Repository 不要返回 HttpResponse

错误:


repository.getOrders()

↓

返回

HttpResponse

页面:

开始:

判断:


response.code

Repository:

失去:

意义。

正确:

Repository:

应该:

返回:

业务数据。

例如:


Order[]

或者:


User

而不是:

Http对象。


十一、Repository 不要关心 UI

错误:


Loading.show()

写:

Repository。

或者:


Toast.show()

写:

Repository。

Repository:

不知道:

页面。

否则:

以后:

单元测试:

全部失败。


十二、Repository 与 ViewModel 的职责

很多新人:

容易:

写反。

正确:

如下:

ViewModel Repository
页面状态 数据获取
Loading状态 网络请求
Button点击 数据缓存
页面刷新 数据同步
UI逻辑 网络逻辑

一句话:

ViewModel:

负责:

页面。

Repository:

负责:

数据。


十三、Repository 最佳实践

企业:

推荐:

一个:

Feature:

一个:

Repository。

例如:


feature_order

↓

OrderRepository

里面:

管理:


订单

退款

售后

物流

不要:

拆:


RefundRepository

ExpressRepository

EvaluateRepository

太细。

维护:

困难。


十四、Repository + HSP

如果:

多个:

Feature:

共享:

Repository。

例如:

账号。

可以:

放:


core_account(HSP)

↓

AccountRepository

订单:

登录:

支付:

共同:

依赖。


十五、完整企业架构


                OrderPage

                     │

                     ▼

             OrderViewModel

                     │

                     ▼

             OrderRepository

          ┌────────┴────────┐

          ▼                 ▼

LocalDataSource     RemoteDataSource

          ▼                 ▼

      Database         HttpClient

这就是目前企业项目最主流的 Repository 架构。


十六、Repository 常见错误

错误一:Repository 写 SQL

如果数据库操作复杂,可以进一步抽出 DAO(Data Access Object)层,让 Repository 只负责业务编排。


Repository
      │
      ▼
    DAO
      │
      ▼
 Database

错误二:Repository 调用 Router

例如:


router.pushUrl()

Repository:

不能:

跳页面。


错误三:Repository 操作组件

例如:


Dialog.show()

不能。


错误四:Repository 保存页面状态

例如:


isLoading=true

应该:

ViewModel。


十七、企业目录推荐


feature_order
│
├── pages
│
├── components
│
├── viewmodel
│
├── repository
│     └── OrderRepository.ets
│
├── datasource
│     ├── LocalDataSource.ets
│     ├── RemoteDataSource.ets
│     └── CacheDataSource.ets
│
├── dao
│     └── OrderDao.ets
│
├── model
│
├── service
│
└── Index.ets

对于大型项目,这种结构既能保持职责清晰,又方便后续扩展。


本章总结

本章详细讲解了 HarmonyOS 企业级 Repository 设计,重点包括:

  • Repository 的定位与职责;
  • Repository 与 ViewModel、Network 的边界;
  • Repository + DataSource + DAO 分层设计;
  • 为什么 Repository 不应该依赖 UI;
  • 多数据源(网络、缓存、数据库)的统一管理;
  • 企业项目推荐的目录结构。

核心原则:

Repository 负责"数据从哪里来",ViewModel 负责"数据怎么展示",View 负责"数据如何呈现"。

三者职责越清晰,项目越容易维护。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐