设计大型 ArkTS 工程(如 HarmonyOS 元服务或大型应用)时,核心挑战在于如何平衡极致的性能与解耦的开发体验。ArkTS 的静态特性要求我们在架构设计上比传统的 JS/TS 更加严谨。
以下是针对大型工程推荐的架构模式与解耦策略。
1. 推荐架构:分层模块化 (Layered Modular Architecture)
大型工程应遵循 三层架构模型,通过 ohpm 共享包(HAR/HSP)进行物理隔离:
- 产品层 (Product): 具体的 App 壳,负责集成各个 Feature。
- 特性层 (Feature): 独立的业务模块(如 购物、个人中心、聊天)。Feature 之间禁止直接依赖。
- 基础层 (Common/Base): 网络库、UI 组件库、工具类、核心数据模型。
2. 如何避免组件过度耦合?
在声明式 UI 中,组件很容易因为深层传递 Props 而陷入耦合。
A. 容器组件与展示组件分离 (Container & Presentational)
- 展示组件: 只负责 UI,通过
@Prop接收数据,通过Callback弹出事件。不感知业务逻辑。 - 容器组件: 负责逻辑处理、数据请求、状态管理。它包裹展示组件并注入数据。
B. 使用命令式控制器 (Controller Pattern)
对于复杂的 UI 组件(如自定义播放器),不要把所有逻辑塞进 @Component。定义一个 MyComponentController 类,通过构造函数传入,实现逻辑与视图的解耦。
C. 依赖注入 (DI) 的思想
不要在组件内部直接 new 一个复杂的业务对象。尝试通过构造参数或 @Provide 注入接口实现,方便单元测试和模块替换。
3. 如何实现跨 Feature 状态共享?
跨 Feature 共享是大型工程的痛点。ArkTS 提供了由浅入深的四种方案:
方案一:AppStorage (全局状态中心)
适合存储全应用通用的简单状态(如:登录用户信息、夜间模式)。
- 优点: 简单直接,响应式更新。
- 缺点: 容易变成“垃圾场”,缺乏类型约束,且在多实例(多 Ability)下有局限。
方案二:LocalStorage (页面级/组件树级)
适合在同一个 Feature 内部的不同页面间共享状态。它比 AppStorage 更安全,生命周期跟随 UI 实例。
方案三:Emitter / EventHub (事件驱动)
适合完全解耦的 Feature 通信。
- 场景: 购物车模块(Feature A)更新了数量,个人中心(Feature B)需要更新红点。
- 实现: Feature A 发布事件,Feature B 订阅。它们不需要知道彼此的存在。
方案四:单例 Service + @Observed/@ObjectLink (进阶推荐)
在 Base 层定义共享的 DataModel 类,并使用 @Observed 装饰。
- 创建一个单例
DataService。 - 各 Feature 引用该单例中的数据对象。
- 配合
@ObjectLink实现跨模块的精准局部刷新。
4. 关键实践:如何处理跨模块跳转?
为了避免 Feature A 直接 import Feature B 导致循环依赖,推荐使用 路由解耦 (Router Mapping) :
- 路由表: 在 Base 层维护一个字符串常量表(如
RoutePath.LOGIN_PAGE = 'pages/Login')。 - 动态跳转: 使用系统提供的
router或Navigation组件,通过字符串路径跳转,而不是直接引用组件类。
总结
| 维度 | 解决方案 |
|---|---|
| 物理结构 | 使用 HSP (Harmony Shared Package) 减少内存占用。 |
| 组件解耦 | 坚持 单向数据流,减少 @Link 的滥用。 |
| 逻辑复用 | 将非 UI 逻辑抽离到纯静态类或 Service 中。 |
| 状态共享 | 优先用 Emitter 解耦,复杂状态用 @Observed 单例。 |
架构建议: 永远不要让两个业务 Feature 互相 import。如果它们需要共享代码,请将代码下沉到 Common 层;如果它们需要通信,请使用事件总线或路由中心。