【HarmonyOS实战开发】鸿蒙中实现组件化通信解耦

199 篇文章 0 订阅
198 篇文章 0 订阅

1、前言

在鸿蒙项目初期开发中,我们的代码结构可能是这样,features功能模块目录中,涉及到所有功能模块都调用的功能,都放到【公共功能】har中。但是,随着功能的不断增加,和时间推移。这种结构可能会有以下几种问题。

1.公共功能har,代码臃肿,业务耦合严重,维护成本增加
2.公共功能har,功能无法拆分,假如有手机、手表、汽车三种产品。公共功能har中不同产品可能需3.要得功能也是不一样的。无法做到产品功能隔离
4.实现一个功能,还要去改动很多别人模块的代码?

修改某个历史功能,但不知不觉导致其他模块出现bug?
在这里插入图片描述

有没有方法能完全隔离各功能之间的业务模块,通讯之间通过一定协议规则来约束,业务部门开发过程中只专注自己的模块,从物理上杜绝跨业务修改代码?

2、组件化理解

组件化,去除模块间Module[har]的耦合,使得每个业务模块Module[har]可以独立当做App[通过hap壳工程引入]存在,对于其他模块没有直接的依赖关系。 此时业务模块就成为了业务组件。
除了业务组件,还有抽离出来的业务基础组件,是提供给业务组件使用,但不是独立的业务,例如分享组件、广告组件;还有基础组件,即单独的基础功能,与业务无关,例如 图片加载、网络请求等。

组件化带来的好处

1提高协作效率:解耦 使得组件之间 彼此互不打扰,组件内部代码相关性极高。 团队中每个人有自己的责任组件,不会影响其他组件;降低团队成员熟悉项目的成本,只需熟悉责任组件即可;对测2试来说,只需重点测试改动的组件,而不是全盘回归测试。

2.功能重用:组件 类似我们引用的第三方库,只需维护好每个组件,一建引用集成即可。业务组件可上可下,灵活多变;而基础组件,为新业务随时集成提供了基础,减少重复开发和维护工作量。

下图是我们期望的组件化架构:
在这里插入图片描述

1.组件依赖关系上层依赖下层,修改频率上层高于下层。

2.基础组件是通用基础能力,修改频率极低,作为SDK可共公司所有项目集成使用。

3.module_common组件,作为支撑业务组件、业务基础组件的基础,同时依赖所有的基础组件,提供多数业务组件需要的基本功能,并且统一了基础组件的版本号。所以 业务组件、业务基础组件 所需的基础能力只需要依赖common组件即可获得。【组件化通信的核心就是common 组件】

4.业务组件、业务基础组件,都依赖common组件。但业务组件之间不存在依赖关系,业务基础组件之间不存在依赖关系。而 业务组件 是依赖所需的业务基础组件的,例如几乎所有业务组件都会依赖广告组件 来展示Banner广告、弹窗广告等。

3、 组件化开发的问题点

在深入探讨组件化的原则与策略之际,我们已然领悟到了组件化理念的核心所在,以及其所蕴含的优势与结构特性。在此之后,倘若我们欲将组件化的理念付诸实践,首要的任务便是清晰地界定我们需要解决的一系列挑战。

首要任务是确保业务组件的解耦性。解耦性,乃是构建一个健壯、可维护系统的关键。在此过程中,我们首先需识别可能存在的耦合形式,举例来说,即是页面间的导航跳转、方法之间的互相调用,以及不同组件间的事件通讯机制。显而易见,对于基本组件及业务基础组件,这些耦合问题并非其首要挑战,故此我们可以将其视为封装成库的候选之列,从而实现代码的复用与模块化管理。
然而,当我们的目光转向业务组件时,问题则更为复杂。对于这一层面,我们需面对的问题庞杂且具体,具体细节如下:

1.各业务组件并无牵连,如何实现画面间的顺畅跳转?
2.在没有相互依赖的前提下,各组件应如何实现通信与方法的相互调用?
接下来,让我们一探究竟,解答上述诸多疑惑。

3.1 页面跳转

使用框架ZRouter,ZRouter是基于Navigation系统路由表和Hvigor插件实现的动态路由方案。
两行代码就可以完成页面的跳转,如下:
在这里插入图片描述
新建三个模块分别是harA、harB、hspC,三者之间没有依赖关系,entry模块依赖了这三个模块,通过ZRouter可以在四个模块间相互跳转,从而达到模块解耦效果。模块关系图如下图:
在这里插入图片描述

3.2 组件化通信

组件之间虽缺乏直接依赖,互通却又势在必行。譬如,主页须展示购物车内物品之数目,然查询此数目之能,独属于购物车组件之内部。于此情形,我们该如何是好呢?

3.2.1 新建组件通信服务module

也可以不用新建,放到module_common也行
library_service

IClassConstructor.ts
/**
 * 用于拿到Class 类,然后实例化
 * @author Tanranran
 * @description
 */
export interface IClassConstructor<T> {
  new(...args: any[]): T
}
/**
 * A module 要向外暴露的方法
 * @author Tanranran
 * @description
 */

export interface IRouterAService{
  showAmoduleToast(): void
}
/**
 * B module 要向外暴露的方法
 * @author Tanranran
 * @description
 */
export interface IRouterBService{
  showBModuleToast(): void
}
/**
 *  跨模块module 调用方法的 service 工具类
 * @author Tanranran
 * @description
 */
import { IClassConstructor } from './IClassConstructor';
import { IRouterBService } from './IRouterBService';
import { IRouterAService } from './IRouterAService';


export class ZZServices {
  private static routerHomeService?: IRouterAService;
  private static routerHaoJiaService?: IRouterBService;
  private static servicesMap = new Map<ZZServices.ServiceName, ZZServices.ServiceProvider>()

  static getAService(): IRouterAService | undefined {
    if (ZZServices.routerHomeService) {
      return ZZServices.routerHomeService
    }
    if (ZZServices.servicesMap.has(ZZServices.ServiceName.AService)) {
      const service = ZZServices.servicesMap.get(ZZServices.ServiceName.AService)
      if (service) {
        ZZServices.routerHomeService = service as object as IRouterAService;
      }
    }
    return ZZServices.routerHomeService
  }

  static getBService(): IRouterBService | undefined {
    if (ZZServices.routerHaoJiaService) {
      return ZZServices.routerHaoJiaService
    }
    if (ZZServices.servicesMap.has(ZZServices.ServiceName.BService)) {
      const service = ZZServices.servicesMap.get(ZZServices.ServiceName.BService)
      if (service) {
        ZZServices.routerHaoJiaService = service as object as IRouterBService;
      }
    }
    return ZZServices.routerHaoJiaService
  }

  public static addService<T extends ZZServices.ServiceProvider>(name: ZZServices.ServiceName,
    cls: IClassConstructor<T>) {
    let provider = new cls()
    ZZServices.servicesMap.set(name, provider)
    provider.register()
  }
}

export namespace ZZServices {
  /**
   * 要注册的服务名称
   */
  export enum ServiceName {
    AService = 'AService',
    BService = 'BService'
  }

  /**
   * @author Tanranran
   * @description
   */
  export abstract class ServiceProvider {
    // 在此期间注册服务,预留,可以干一些服务注册时,你想干的事
    register() {

    }
  }
}

3.2.2 业务module 实现接口

module_a
import { IRouterAService, ZZServices } from '@ranran/library_service';
import { promptAction } from '@kit.ArkUI';

export class RouterAService extends ZZServices.ServiceProvider implements IRouterAService {
  showAmoduleToast(): void {
    promptAction.showToast({
      message: "我是来自首页Module的Toast"
    })
  }
}
module_b
import { IRouterBService, ZZServices } from '@ranran/library_service/';
import { promptAction } from '@kit.ArkUI';

export class RouterBService extends ZZServices.ServiceProvider implements IRouterBService {
  showBModuleToast(): void {
    promptAction.showToast({
      message: "我是来自好价Module的Toast"
    })
  }
}

3.2.3 其它module调用组件化方法

这里用entry来举例,也可以自己新建一个module 来调用

import { ZZServices } from '@ranran/library_service';
import { RouterAService } from '@ranran/module_a';
import { RouterBService } from '@ranran/module_b';

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  aboutToAppear(): void {
    ZZServices.addService(ZZServices.ServiceName.AService, RouterAService)
    ZZServices.addService(ZZServices.ServiceName.BService, RouterBService)
  }

  build() {
    Column() {
      Button('调用A module中的方法').onClick(() => {
        ZZServices.getAService()?.showAmoduleToast()
      })
      Button('调用B module中的方法').onClick(() => {
        ZZServices.getBService()?.showBModuleToast()
      })
    }
    .height('100%')
    .width('100%')
  }
}

4、其实还有很多优化空间

1.通过注解动态注册服务
2.每个组件module单独可运行
3…

写在最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)文档用来跟着学习是非常有必要的。

这份鸿蒙(HarmonyOS NEXT)文档包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

希望这一份鸿蒙学习文档能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习文档

鸿蒙(HarmonyOS NEXT)5.0最新学习路线

在这里插入图片描述

有了路线图,怎么能没有学习文档呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习文档

《鸿蒙 (OpenHarmony)开发入门教学视频》

在这里插入图片描述

《鸿蒙生态应用开发V3.0白皮书》

在这里插入图片描述

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

在这里插入图片描述

《鸿蒙开发基础》

●ArkTS语言
●安装DevEco Studio
●运用你的第一个ArkTS应用
●ArkUI声明式UI开发
.……
在这里插入图片描述

《鸿蒙开发进阶》

●Stage模型入门
●网络管理
●数据管理
●电话服务
●分布式应用开发
●通知与窗口管理
●多媒体技术
●安全技能
●任务管理
●WebGL
●国际化开发
●应用测试
●DFX面向未来设计
●鸿蒙系统移植和裁剪定制
……
在这里插入图片描述

《鸿蒙进阶实战》

●ArkTS实践
●UIAbility应用
●网络案例
……
在这里插入图片描述

获取以上完整鸿蒙HarmonyOS学习文档,请点击→纯血版全套鸿蒙HarmonyOS学习文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值