Harmony 开发中的三层架构

93 阅读4分钟

三层工程结构 是鸿蒙应用开发中推荐的 模块化分层架构,主要用于复杂应用的代码组织,强调模块解耦复用性。这一架构与操作系统内核的分层不同,聚焦于 应用工程本身的结构设计。以下是详细的层级说明、依赖规则和实际应用场景分析:


三层工程结构

1736818004533.png

  • commons(公共能力层):用于存放公共基础能力集合(如工具库、公共配置等)。commons层可编译成一个或多个HAR包或HSP包,只可以被products和features依赖,不可以反向依赖。

  • features(基础特性层):用于存放基础特性集合(如应用中相对独立的各个功能的UI及业务逻辑实现等)。各个feature高内聚、低耦合、可定制,供产品灵活部署。不需要单独部署的feature通常编译为HAR包或HSP包,供products或其它feature使用。需要单独部署的feature通常编译为Feature类型的HAP包,和products下Entry类型的HAP包进行组合部署。features层可以横向调用及依赖common层,同时可以被products层不同设备形态的HAP所依赖,但是不能反向依赖products层。

  • products(产品定制层):用于针对不同设备形态进行功能和特性集成。products层各个子目录各自编译为一个Entry类型的HAP包,作为应用主入口。products层不可以横向调用。

上方的图和解释来源于鸿蒙官方文档 详情看这里鸿蒙三层架构官方文档,下边是自己进行的一个总结,如果有错误欢迎指出。

一、三层工程结构定义

graph TD
  A[commons] -->|被依赖| B[features]
  A -->|被依赖| C[products]
  B -->|被依赖| C
  B -->|横向依赖| B

1. commons(公共能力层)

  • 定位:基础能力沉淀层,存放 全局共享工具、通用组件、基础服务
  • 输出形式:编译为 HAR(静态共享包)HSP(动态共享包)
  • 依赖规则
    • 不可被反向依赖:commons 层不依赖上层(features/products)。
    • 禁止业务逻辑:仅包含与业务无关的公共代码。

典型内容

  • 工具类:LoggerNetworkUtilsStorageHelper
  • 通用组件:自定义按钮、弹窗模板
  • 基础配置:全局样式、路由表

代码示例

// commons/src/main/ets/utils/Logger.ets
export class Logger {
  static info(message: string): void {
    console.log(`[INFO] ${message}`);
  }
}

2. features(基础特性层)

  • 定位:功能模块集合层,每个模块 高内聚、可独立运行/测试
  • 输出形式
    • 非独立部署:编译为 HAR/HSP 供其他模块复用。
    • 独立部署:编译为 Feature 类型 HAP(动态按需加载)。
  • 依赖规则
    • 可横向依赖:不同 feature 模块可互相调用。
    • 可向下依赖:可引用 commons 层。
    • 不可向上依赖:禁止依赖 products 层。

典型内容

  • 用户模块:user(登录、个人中心)
  • 支付模块:payment(订单、支付)
  • 内容模块:content(文章、视频)

代码示例

// features/user/src/main/ets/LoginPage.ets
import { Logger } from '@commons/utils/Logger';

@Entry
@Component
struct LoginPage {
  build() {
    Column() {
      Button('登录')
        .onClick(() => {
          Logger.info('登录按钮点击');
        })
    }
  }
}

3. products(产品定制层)

  • 定位:设备形态适配层,针对不同设备(手机、手表、平板)整合功能模块
  • 输出形式:编译为 Entry 类型 HAP(应用主入口)。
  • 依赖规则
    • 不可横向依赖:不同 product 模块间隔离。
    • 可向下依赖:可引用 features 和 commons 层。

典型内容

  • phone:手机端入口,整合全功能。
  • watch:手表端入口,仅集成核心功能。
  • tablet:平板端入口,适配大屏布局。

代码示例

// products/phone/src/main/ets/MainAbility.ets
import { LoginPage } from '@features/user';

@Entry
@Component
struct MainAbility {
  build() {
    LoginPage(); // 直接复用 feature 模块
  }
}

二、依赖关系与编译配置

1. 模块依赖声明

在模块的 oh-package.json5 中声明依赖:

// features/user/oh-package.json5
{
  "dependencies": {
    "@commons/utils": "file:../../commons/utils" // 依赖 commons 层
  }
}

2. 编译类型配置

在模块的 build-profile.json5 中定义输出类型:

// products/phone/build-profile.json5
{
  "apiType": "entry", // 标记为 Entry 类型 HAP
  "buildOption": {
    "artifactType": "hap"
  }
}

三、实际应用场景

场景 1:多设备适配

  • 手机端products/phone):集成所有 features。
  • 手表端products/watch):仅集成 user 和基础功能。

场景 2:动态功能加载

  • 将低频功能(如 payment)编译为 Feature HAP,用户使用时按需下载。

场景 3:团队协作

  • 不同团队负责独立 feature 模块,通过 HAR/HSP 共享代码。

四、优势与最佳实践

优势实现方式
模块解耦严格依赖规则(禁止反向/循环依赖)
代码复用通过 HAR/HSP 共享公共代码
灵活部署Entry HAP + Feature HAP 组合
编译加速独立模块增量编译

最佳实践

  1. 避免跨层直调:通过接口或事件通信,而非直接引用。
  2. 版本统一管理:使用 ohpm 管理公共库版本。
  3. 按需拆包:对高频功能使用 HSP 动态加载。

五、常见错误示例

错误 1:反向依赖

// commons 层错误依赖 feature
import { LoginService } from '@features/user'; // ❌ 违反依赖规则

错误 2:循环依赖

graph TD
  A[featureA] -->|依赖| B[featureB]
  B -->|依赖| A

解决方案:将公共逻辑下沉至 commons 层。