HarmonyOS NEXT 统一 ToolManager 架构:插件化工具系统的设计与实现
HarmonyOS NEXT 统一 ToolManager 架构:插件化工具系统的设计与实现
前言
在 HarmonyExplorer 项目中,工具箱模块集成了文件压缩、格式转换、哈希计算等多种实用工具。随着工具数量增长,如何避免代码臃肿、实现工具的动态扩展成为架构设计的核心挑战。本文将详细讲解基于插件化理念的统一 ToolManager 架构设计,实现新增工具零侵入式扩展。参考 ArkTS 接口定义规范 了解接口设计要点。
一、ToolManager 架构设计理念
1.1 传统工具管理的痛点
在未引入 ToolManager 之前,工具箱页面通过 if-else 或 switch-case 硬编码管理工具调用。这种方式存在以下问题:
| 问题 | 影响 | 严重程度 |
|---|---|---|
| 新增工具需修改核心代码 | 违反开闭原则 | 高 |
| 工具间无法统一管理 | 维护成本高 | 中 |
| 工具历史记录分散 | 数据不一致 | 中 |
| 工具间无法共享数据 | 代码重复 | 低 |
1.2 插件化设计目标
ToolManager 的设计目标是构建一个 高内聚、低耦合 的工具管理系统:
- 零侵入扩展:新增工具只需实现接口并注册,无需修改已有代码
- 统一管理:所有工具的发现、加载、执行、历史记录统一处理
- 分类组织:工具按类别管理,支持动态分组展示
- 生命周期管理:工具的初始化、执行、销毁全程可控
插件化架构的核心价值在于将变化隔离,让系统在不修改稳定核心的前提下灵活扩展新能力。
二、插件化接口设计 ITool
2.1 ITool 接口定义
所有工具必须实现 ITool 接口,该接口定义了工具的生命周期方法和元数据。接口设计是整个架构的基石。
export enum ToolCategory {
FILE = 'file',
IMAGE = 'image',
MEDIA = 'media',
SECURITY = 'security',
UTIL = 'util'
}
export interface ToolResult {
success: boolean;
data: string;
message: string;
}
export interface ToolMetadata {
id: string;
name: string;
description: string;
category: ToolCategory;
icon: Resource;
isAvailable: boolean;
}
export interface ITool {
getMetadata(): ToolMetadata;
execute(input: string): Promise<ToolResult>;
onActivate(): void;
onDeactivate(): void;
}
2.2 抽象基类实现
为了减少重复代码,提供 AbstractTool 抽象基类,子类只需关注核心执行逻辑:
export abstract class AbstractTool implements ITool {
protected metadata: ToolMetadata;
constructor(metadata: ToolMetadata) {
this.metadata = metadata;
}
getMetadata(): ToolMetadata {
return this.metadata;
}
abstract execute(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) 查找效率。
export class ToolManager {
private static tools: Map<string, ITool> = new Map();
private static categoryIndex: Map<ToolCategory, Array<string>> = new Map();
static register(tool: ITool): void {
const metadata: ToolMetadata = tool.getMetadata();
this.tools.set(metadata.id, tool);
this.addToCategoryIndex(metadata.category, metadata.id);
LogUtil.info('工具注册成功: ' + metadata.name);
}
static unregister(toolId: string): void {
const tool: ITool | undefined = this.tools.get(toolId);
if (tool !== undefined) {
const metadata: ToolMetadata = tool.getMetadata();
this.removeFromCategoryIndex(metadata.category, toolId);
tool.onDeactivate();
this.tools.delete(toolId);
}
}
private static addToCategoryIndex(category: ToolCategory, toolId: string): void {
let ids: Array<string> | undefined = this.categoryIndex.get(category);
if (ids === undefined) {
ids = [];
this.categoryIndex.set(category, ids);
}
ids.push(toolId);
}
private static removeFromCategoryIndex(category: ToolCategory, toolId: string): void {
const ids: Array<string> | undefined = this.categoryIndex.get(category);
if (ids !== undefined) {
const index: number = ids.indexOf(toolId);
if (index >= 0) {
ids.splice(index, 1);
}
}
}
}
3.2 工具发现与加载
工具注册在应用初始化时自动完成。通过 ToolRegistry 集中管理所有工具的注册调用:
export class ToolRegistry {
static initAllTools(): void {
ToolManager.register(new FileCompressTool());
ToolManager.register(new FileHashTool());
ToolManager.register(new ImageConvertTool());
ToolManager.register(new AudioConvertTool());
ToolManager.register(new Base64Tool());
LogUtil.info('所有工具注册完成');
}
}
四、具体工具实现示例
4.1 文件压缩工具
以下展示一个完整的工具实现,继承 AbstractTool 并实现 execute 方法:
export class FileCompressTool extends AbstractTool {
constructor() {
super({
id: 'tool_file_compress',
name: '文件压缩',
description: '支持 ZIP 格式文件压缩',
category: ToolCategory.FILE,
icon: $r('app.media.ic_tool_compress'),
isAvailable: true
});
}
async execute(input: string): Promise<ToolResult> {
try {
const targetPath: string = input + '.zip';
const success: boolean = await ZipManager.compressFiles(input, targetPath);
return {
success: success,
data: targetPath,
message: success ? '压缩成功' : '压缩失败'
};
} catch (error) {
return {
success: false,
data: '',
message: '压缩异常: ' + error.message
};
}
}
}
4.2 文件哈希工具
export class FileHashTool extends AbstractTool {
constructor() {
super({
id: 'tool_file_hash',
name: '文件哈希',
description: '计算文件 MD5/SHA256 值',
category: ToolCategory.SECURITY,
icon: $r('app.media.ic_tool_hash'),
isAvailable: true
});
}
async execute(input: string): Promise<ToolResult> {
const hashValue: string = await HashUtil.calculateFileHash(input, 'SHA-256');
return {
success: hashValue.length > 0,
data: hashValue,
message: '哈希计算完成'
};
}
}

图1:ToolManager 插件化架构图,展示接口层、注册层和工具实现层的关系
五、ToolHistory 历史记录
5.1 历史记录模型
每次工具执行后自动记录历史,方便用户查看和复用。ToolHistory 数据模型如下:
export interface ToolHistory {
id: string;
toolName: string;
content: string;
createTime: number;
}
5.2 历史记录管理
import dataPreferences from '@ohos.data.preferences';
export class ToolHistoryRepository {
private static preference: dataPreferences.Preferences | null = null;
private static readonly MAX_HISTORY: number = 100;
static async init(context: Context): Promise<void> {
this.preference = await dataPreferences.getPreferences(context, 'tool_history');
}
static async addHistory(history: ToolHistory): Promise<void> {
if (this.preference === null) { return; }
const key: string = 'history_' + history.id;
await this.preference.put(key, JSON.stringify(history));
await this.preference.flush();
}
static async getHistoryList(): Promise<Array<ToolHistory>> {
if (this.preference === null) { return []; }
const all: Record<string, object> = await this.preference.getAll();
const list: Array<ToolHistory> = [];
const keys: Array<string> = Object.keys(all);
for (const key of keys) {
if (key.startsWith('history_')) {
const history: ToolHistory = JSON.parse(String(all[key]));
list.push(history);
}
}
list.sort((a: ToolHistory, b: ToolHistory) => b.createTime - a.createTime);
return list;
}
}
六、工具分类管理
6.1 分类索引查询
ToolManager 提供按类别查询工具的能力,Toolbox 页面据此进行分组展示。HarmonyExplorer 中预定义的工具分类如下:
| 分类枚举 | 分类名称 | 典型工具示例 |
|---|---|---|
| FILE | 文件工具 | 文件压缩、文件哈希 |
| IMAGE | 图片工具 | 图片格式转换、图片压缩 |
| MEDIA | 媒体工具 | 音频转换、视频提取 |
| SECURITY | 安全工具 | 文件加密、哈希校验 |
| UTIL | 实用工具 | 二维码生成、Base64 编码 |
export class ToolManager {
static getToolsByCategory(category: ToolCategory): Array<ITool> {
const ids: Array<string> | undefined = this.categoryIndex.get(category);
const result: Array<ITool> = [];
if (ids !== undefined) {
for (const id of ids) {
const tool: ITool | undefined = this.tools.get(id);
if (tool !== undefined && tool.getMetadata().isAvailable) {
result.push(tool);
}
}
}
return result;
}
static getAllCategories(): Array<ToolCategory> {
return Array.from(this.categoryIndex.keys());
}
static async executeTool(toolId: string, input: string): Promise<ToolResult> {
const tool: ITool | undefined = this.tools.get(toolId);
if (tool === undefined) {
return { success: false, data: '', message: '工具不存在' };
}
tool.onActivate();
const result: ToolResult = await tool.execute(input);
const metadata: ToolMetadata = tool.getMetadata();
await ToolHistoryRepository.addHistory({
id: Date.now().toString(), toolName: metadata.name,
content: result.data, createTime: Date.now()
});
tool.onDeactivate();
return result;
}
}
七、ToolCard 组件适配
7.1 组件设计
ToolCard 是工具箱页面的展示组件,直接消费 ToolMetadata 渲染工具卡片。参考 ArkUI 组件开发。
7.2 ToolCard 实现
@Component
export struct ToolCard {
@Prop metadata: 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 管理工具间数据流:
export class ToolContext {
private static dataMap: Map<string, string> = new Map();
static setData(key: string, value: string): void {
this.dataMap.set(key, value);
}
static getData(key: string): string {
return this.dataMap.get(key) ?? '';
}
static clearData(key: string): void {
this.dataMap.delete(key);
}
static clearAll(): 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 协作示例
export class ImageConvertTool extends AbstractTool {
constructor() {
super({
id: 'tool_image_convert',
name: '图片格式转换',
description: '支持 PNG/JPEG/WebP 互转',
category: ToolCategory.IMAGE,
icon: $r('app.media.ic_tool_convert'),
isAvailable: true
});
}
async execute(input: string): Promise<ToolResult> {
const params: ConvertParams = {
sourcePath: input,
targetFormat: ImageFormat.JPEG,
quality: 90
};
const result: ConvertResult = await KitManager.getImageKit().convertFormat(params);
return {
success: result.success,
data: result.outputPath,
message: result.message
};
}
}
十、新增工具流程
10.1 零侵入扩展步骤
新增一个工具的完整流程如下:
- 创建工具类,继承 AbstractTool
- 实现 execute 方法编写核心逻辑
- 在 ToolRegistry.initAllTools 中添加注册调用
- 无需修改 Toolbox 页面、ToolCard 组件等已有代码
// 步骤1-2: 创建新工具
export class QrCodeTool extends AbstractTool {
constructor() {
super({
id: 'tool_qrcode',
name: '二维码生成',
description: '将文本生成二维码图片',
category: ToolCategory.UTIL,
icon: $r('app.media.ic_tool_qrcode'),
isAvailable: true
});
}
async execute(input: string): Promise<ToolResult> {
const qrPath: string = await QrCodeUtil.generate(input);
return {
success: qrPath.length > 0,
data: qrPath,
message: '二维码生成成功'
};
}
}
// 步骤3: 在 ToolRegistry.initAllTools 中添加一行注册
ToolManager.register(new QrCodeTool()); // 新增一行即可
整个新增工具过程只需编写一个新类和一行注册代码,完全不影响已有功能,体现了开闭原则的工程实践。
总结
统一 ToolManager 架构是 HarmonyExplorer 项目中插件化设计的核心实践。通过 ITool 接口定义、AbstractTool 基类复用、注册表机制和分类索引,实现了工具的零侵入式扩展。ToolHistory 历史记录和 ToolContext 数据传递机制进一步增强了工具系统的实用性。与 KitManager 的分层协作确保了业务逻辑与系统能力的清晰边界。这一架构使得工具箱模块可以持续扩展而不会导致代码腐化。更多架构设计参考请查阅 HarmonyOS 应用架构指南 和 ArkTS 编程规范。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源
更多推荐

所有评论(0)