HarmonyOS NEXT 统一 ToolManager 架构:插件化工具系统的设计与实现
前言
在 HarmonyExplorer 项目中,工具箱模块集成了文件压缩、格式转换、哈希计算等多种实用工具。随着工具数量增长,如何避免代码臃肿、实现工具的动态扩展成为架构设计的核心挑战。本文将详细讲解基于插件化理念的统一 ToolManager 架构设计,实现新增工具零侵入式扩展。参考 ArkTS 接口定义规范 了解接口设计要点。
一、ToolManager 架构设计理念
1.1 传统工具管理的痛点
在未引入 ToolManager 之前,工具箱页面通过 if-else 或 switch-case 硬编码管理工具调用。这种方式存在以下问题:
| 问题 | 影响 | 严重程度 |
|---|---|---|
| 新增工具需修改核心代码 | 违反开闭原则 | 高 |
| 工具间无法统一管理 | 维护成本高 | 中 |
| 工具历史记录分散 | 数据不一致 | 中 |
| 工具间无法共享数据 | 代码重复 | 低 |
1.2 插件化设计目标
ToolManager 的设计目标是构建一个高内聚、低耦合的工具管理系统:
- 零侵入扩展:新增工具只需实现接口并注册,无需修改已有代码
- 统一管理:所有工具的发现、加载、执行、历史记录统一处理
- 分类组织:工具按类别管理,支持动态分组展示
- 生命周期管理:工具的初始化、执行、销毁全程可控
插件化架构的核心价值在于将变化隔离,让系统在不修改稳定核心的前提下灵活扩展新能力。
二、插件化接口设计 ITool
2.1 ITool 接口定义
所有工具必须实现 ITool 接口,该接口定义了工具的生命周期方法和元数据。接口设计是整个架构的基石。
exportenumToolCategory{FILE='file',IMAGE='image',MEDIA='media',SECURITY='security',UTIL='util'}exportinterfaceToolResult{success:boolean;data:string;message:string;}exportinterfaceToolMetadata{id:string;name:string;description:string;category:ToolCategory;icon:Resource;isAvailable:boolean;}exportinterfaceITool{getMetadata():ToolMetadata;execute(input:string):Promise<ToolResult>;onActivate():void;onDeactivate():void;}2.2 抽象基类实现
为了减少重复代码,提供 AbstractTool 抽象基类,子类只需关注核心执行逻辑:
exportabstractclassAbstractToolimplementsITool{protectedmetadata:ToolMetadata;constructor(metadata:ToolMetadata){this.metadata=metadata;}getMetadata():ToolMetadata{returnthis.metadata;}abstractexecute(input:string):Promise<ToolResult>;onActivate():void{LogUtil.info('工具激活: '+this.metadata.name);}onDeactivate():void{LogUtil.info('工具停用: '+this.metadata.name);}}三、工具注册机制
3.1 注册器设计
ToolManager 内部维护一个工具注册表,支持按 ID 和类别检索。注册采用 Map 结构保证 O(1) 查找效率。
exportclassToolManager{privatestatictools:Map<string,ITool>=newMap();privatestaticcategoryIndex:Map<ToolCategory,Array<string>>=newMap();staticregister(tool:ITool):void{constmetadata:ToolMetadata=tool.getMetadata();this.tools.set(metadata.id,tool);this.addToCategoryIndex(metadata.category,metadata.id);LogUtil.info('工具注册成功: '+metadata.name);}staticunregister(toolId:string):void{consttool:ITool|undefined=this.tools.get(toolId);if(tool!==undefined){constmetadata:ToolMetadata=tool.getMetadata();this.removeFromCategoryIndex(metadata.category,toolId);tool.onDeactivate();this.tools.delete(toolId);}}privatestaticaddToCategoryIndex(category:ToolCategory,toolId:string):void{letids:Array<string>|undefined=this.categoryIndex.get(category);if(ids===undefined){ids=[];this.categoryIndex.set(category,ids);}ids.push(toolId);}privatestaticremoveFromCategoryIndex(category:ToolCategory,toolId:string):void{constids:Array<string>|undefined=this.categoryIndex.get(category);if(ids!==undefined){constindex:number=ids.indexOf(toolId);if(index>=0){ids.splice(index,1);}}}}3.2 工具发现与加载
工具注册在应用初始化时自动完成。通过 ToolRegistry 集中管理所有工具的注册调用:
exportclassToolRegistry{staticinitAllTools():void{ToolManager.register(newFileCompressTool());ToolManager.register(newFileHashTool());ToolManager.register(newImageConvertTool());ToolManager.register(newAudioConvertTool());ToolManager.register(newBase64Tool());LogUtil.info('所有工具注册完成');}}四、具体工具实现示例
4.1 文件压缩工具
以下展示一个完整的工具实现,继承 AbstractTool 并实现 execute 方法:
exportclassFileCompressToolextendsAbstractTool{constructor(){super({id:'tool_file_compress',name:'文件压缩',description:'支持 ZIP 格式文件压缩',category:ToolCategory.FILE,icon:$r('app.media.ic_tool_compress'),isAvailable:true});}asyncexecute(input:string):Promise<ToolResult>{try{consttargetPath:string=input+'.zip';constsuccess:boolean=awaitZipManager.compressFiles(input,targetPath);return{success:success,data:targetPath,message:success?'压缩成功':'压缩失败'};}catch(error){return{success:false,data:'',message:'压缩异常: '+error.message};}}}4.2 文件哈希工具
exportclassFileHashToolextendsAbstractTool{constructor(){super({id:'tool_file_hash',name:'文件哈希',description:'计算文件 MD5/SHA256 值',category:ToolCategory.SECURITY,icon:$r('app.media.ic_tool_hash'),isAvailable:true});}asyncexecute(input:string):Promise<ToolResult>{consthashValue:string=awaitHashUtil.calculateFileHash(input,'SHA-256');return{success:hashValue.length>0,data:hashValue,message:'哈希计算完成'};}}图1:ToolManager 插件化架构图,展示接口层、注册层和工具实现层的关系
五、ToolHistory 历史记录
5.1 历史记录模型
每次工具执行后自动记录历史,方便用户查看和复用。ToolHistory 数据模型如下:
exportinterfaceToolHistory{id:string;toolName:string;content:string;createTime:number;}5.2 历史记录管理
importdataPreferencesfrom'@ohos.data.preferences';exportclassToolHistoryRepository{privatestaticpreference:dataPreferences.Preferences|null=null;privatestaticreadonlyMAX_HISTORY:number=100;staticasyncinit(context:Context):Promise<void>{this.preference=awaitdataPreferences.getPreferences(context,'tool_history');}staticasyncaddHistory(history:ToolHistory):Promise<void>{if(this.preference===null){return;}constkey:string='history_'+history.id;awaitthis.preference.put(key,JSON.stringify(history));awaitthis.preference.flush();}staticasyncgetHistoryList():Promise<Array<ToolHistory>>{if(this.preference===null){return[];}constall:Record<string,object>=awaitthis.preference.getAll();constlist:Array<ToolHistory>=[];constkeys:Array<string>=Object.keys(all);for(constkeyofkeys){if(key.startsWith('history_')){consthistory:ToolHistory=JSON.parse(String(all[key]));list.push(history);}}list.sort((a:ToolHistory,b:ToolHistory)=>b.createTime-a.createTime);returnlist;}}六、工具分类管理
6.1 分类索引查询
ToolManager 提供按类别查询工具的能力,Toolbox 页面据此进行分组展示。HarmonyExplorer 中预定义的工具分类如下:
| 分类枚举 | 分类名称 | 典型工具示例 |
|---|---|---|
| FILE | 文件工具 | 文件压缩、文件哈希 |
| IMAGE | 图片工具 | 图片格式转换、图片压缩 |
| MEDIA | 媒体工具 | 音频转换、视频提取 |
| SECURITY | 安全工具 | 文件加密、哈希校验 |
| UTIL | 实用工具 | 二维码生成、Base64 编码 |
exportclassToolManager{staticgetToolsByCategory(category:ToolCategory):Array<ITool>{constids:Array<string>|undefined=this.categoryIndex.get(category);constresult:Array<ITool>=[];if(ids!==undefined){for(constidofids){consttool:ITool|undefined=this.tools.get(id);if(tool!==undefined&&tool.getMetadata().isAvailable){result.push(tool);}}}returnresult;}staticgetAllCategories():Array<ToolCategory>{returnArray.from(this.categoryIndex.keys());}staticasyncexecuteTool(toolId:string,input:string):Promise<ToolResult>{consttool:ITool|undefined=this.tools.get(toolId);if(tool===undefined){return{success:false,data:'',message:'工具不存在'};}tool.onActivate();constresult:ToolResult=awaittool.execute(input);constmetadata:ToolMetadata=tool.getMetadata();awaitToolHistoryRepository.addHistory({id:Date.now().toString(),toolName:metadata.name,content:result.data,createTime:Date.now()});tool.onDeactivate();returnresult;}}七、ToolCard 组件适配
7.1 组件设计
ToolCard 是工具箱页面的展示组件,直接消费 ToolMetadata 渲染工具卡片。参考 ArkUI 组件开发。
7.2 ToolCard 实现
@Componentexportstruct ToolCard{@Propmetadata:ToolMetadata;onToolClick:(toolId:string)=>void=()=>{};build():void{Column(){Image(this.metadata.icon).width(40).height(40).margin({bottom:8})Text(this.metadata.name).fontSize(13).fontColor($r('app.color.text_primary')).maxLines(1)Text(this.metadata.description).fontSize(11).fontColor($r('app.color.text_secondary')).maxLines(2).margin({top:2})}.width('100%').padding(12).borderRadius(12).backgroundColor($r('app.color.bg_card')).alignItems(HorizontalAlign.Center).opacity(this.metadata.isAvailable?1.0:0.4).onClick(()=>{if(this.metadata.isAvailable){this.onToolClick(this.metadata.id);}})}}八、工具间数据传递
8.1 数据传递机制
某些工具的输出可以作为另一个工具的输入,例如哈希计算结果可以传递给 Base64 编码工具。ToolManager 提供 ToolContext 管理工具间数据流:
exportclassToolContext{privatestaticdataMap:Map<string,string>=newMap();staticsetData(key:string,value:string):void{this.dataMap.set(key,value);}staticgetData(key:string):string{returnthis.dataMap.get(key)??'';}staticclearData(key:string):void{this.dataMap.delete(key);}staticclearAll():void{this.dataMap.clear();}}工具间数据传递采用键值对存储模式,解耦了工具之间的直接依赖,任何工具都可以生产或消费数据。
九、ToolManager 与 KitManager 协作
9.1 职责边界
ToolManager 管理工具的注册与执行流程,KitManager 管理 HarmonyOS Kit 的能力封装。两者协作关系如下:
- 工具执行时通过 ToolManager 调度
- 工具内部调用 KitManager 获取系统能力
- KitManager 封装 File Kit、Image Kit 等底层 API
- ToolManager 记录执行历史,KitManager 不感知业务逻辑
| 维度 | ToolManager | KitManager |
|---|---|---|
| 职责 | 工具生命周期管理 | 系统能力封装 |
| 依赖方向 | 调用 KitManager | 不依赖 ToolManager |
| 扩展方式 | 注册新 ITool | 封装新 Kit |
| 数据管理 | ToolHistory | 无状态 |
9.2 协作示例
exportclassImageConvertToolextendsAbstractTool{constructor(){super({id:'tool_image_convert',name:'图片格式转换',description:'支持 PNG/JPEG/WebP 互转',category:ToolCategory.IMAGE,icon:$r('app.media.ic_tool_convert'),isAvailable:true});}asyncexecute(input:string):Promise<ToolResult>{constparams:ConvertParams={sourcePath:input,targetFormat:ImageFormat.JPEG,quality:90};constresult:ConvertResult=awaitKitManager.getImageKit().convertFormat(params);return{success:result.success,data:result.outputPath,message:result.message};}}十、新增工具流程
10.1 零侵入扩展步骤
新增一个工具的完整流程如下:
- 创建工具类,继承 AbstractTool
- 实现 execute 方法编写核心逻辑
- 在 ToolRegistry.initAllTools 中添加注册调用
- 无需修改 Toolbox 页面、ToolCard 组件等已有代码
// 步骤1-2: 创建新工具exportclassQrCodeToolextendsAbstractTool{constructor(){super({id:'tool_qrcode',name:'二维码生成',description:'将文本生成二维码图片',category:ToolCategory.UTIL,icon:$r('app.media.ic_tool_qrcode'),isAvailable:true});}asyncexecute(input:string):Promise<ToolResult>{constqrPath:string=awaitQrCodeUtil.generate(input);return{success:qrPath.length>0,data:qrPath,message:'二维码生成成功'};}}// 步骤3: 在 ToolRegistry.initAllTools 中添加一行注册ToolManager.register(newQrCodeTool());// 新增一行即可整个新增工具过程只需编写一个新类和一行注册代码,完全不影响已有功能,体现了开闭原则的工程实践。
总结
统一 ToolManager 架构是 HarmonyExplorer 项目中插件化设计的核心实践。通过 ITool 接口定义、AbstractTool 基类复用、注册表机制和分类索引,实现了工具的零侵入式扩展。ToolHistory 历史记录和 ToolContext 数据传递机制进一步增强了工具系统的实用性。与 KitManager 的分层协作确保了业务逻辑与系统能力的清晰边界。这一架构使得工具箱模块可以持续扩展而不会导致代码腐化。更多架构设计参考请查阅 HarmonyOS 应用架构指南 和 ArkTS 编程规范。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源
- HarmonyOS 官方文档
- ArkTS 接口与抽象类
- ArkUI 组件开发指南
- Preferences 数据存储
- CSDN HarmonyOS 架构设计
- HarmonyOS 开源社区