Files
esengine/packages/core/src/Core/PluginServiceRegistry.ts

136 lines
3.8 KiB
TypeScript
Raw Normal View History

refactor(arch): 改进 ServiceToken 设计,统一服务获取模式 (#300) * refactor(arch): 移除全局变量,使用 ServiceToken 模式 - 创建 PluginServiceRegistry 类,提供类型安全的服务注册/获取 - 添加 ProfilerServiceToken 和 CollisionLayerConfigToken - 重构所有 __PROFILER_SERVICE__ 全局变量访问为 getProfilerService() - 重构 __PHYSICS_RAPIER2D__ 全局变量访问为 CollisionLayerConfigToken - 在 Core 类添加 pluginServices 静态属性 - 添加 getService.ts 辅助模块简化服务获取 这是 ServiceToken 模式重构的第一阶段,移除了最常用的两个全局变量。 后续可继续应用到其他模块(Camera/Audio 等)。 * refactor(arch): 改进 ServiceToken 设计,移除重复常量 - tokens.ts: 从 engine-core 导入 createServiceToken(符合规范) - tokens.ts: Token 使用接口 IProfilerService 而非具体类 - 移除 AssetPickerDialog 和 ContentBrowser 中重复的 MANAGED_ASSET_DIRECTORIES - 统一从 editor-core 导入 MANAGED_ASSET_DIRECTORIES * fix(type): 修复 IProfilerService 接口与实现类型不匹配 - 将 ProfilerData 等数据类型移到 tokens.ts 以避免循环依赖 - ProfilerService 显式实现 IProfilerService 接口 - 更新使用方使用 IProfilerService 接口类型而非具体类 * refactor(type): 移除类型重导出,改进类型安全 - 删除 ProfilerService.ts 中的类型重导出,消费方直接从 tokens.ts 导入 - PanelDescriptor 接口添加 titleZh 属性,移除 App.tsx 中的 as any - 改进 useDynamicIcon.ts 的类型安全,使用正确的 Record 类型 * refactor(arch): 为模块添加 ServiceToken 支持 - Material System: 创建 tokens.ts,定义 IMaterialManager 接口和 MaterialManagerToken - Audio: 创建预留 tokens.ts 文件,为未来 AudioManager 服务扩展做准备 - Camera: 创建预留 tokens.ts 文件,为未来 CameraManager 服务扩展做准备 遵循"谁定义接口,谁导出 Token"原则,统一服务访问模式
2025-12-09 11:07:44 +08:00
/**
*
* Plugin Service Registry
*
* ServiceToken
* Type-safe service registry based on ServiceToken.
*
* | Design principles:
* 1. - 使 ServiceToken
* 2. - token
* 3. - get undefinedrequire
* 4. -
* 5. Token - Token
*/
// ============================================================================
// 服务令牌 | Service Token
// ============================================================================
/**
*
* Service token interface
*
*
* For type-safe service registration and retrieval.
*
* __phantom TypeScript
* Note: __phantom is a required property to ensure TypeScript preserves generic
* type information across packages.
*/
export interface ServiceToken<T> {
readonly id: symbol;
readonly name: string;
/**
* Phantom type
* Phantom type marker (enforces type inference)
*/
readonly __phantom: T;
}
/**
*
* Create a service token
*
* @param name | Token name
* @returns | Service token
*/
export function createServiceToken<T>(name: string): ServiceToken<T> {
// __phantom 仅用于类型推断,运行时不需要实际值
// __phantom is only for type inference, no actual value needed at runtime
return {
id: Symbol(name),
name
} as ServiceToken<T>;
}
// ============================================================================
// 插件服务注册表 | Plugin Service Registry
// ============================================================================
/**
*
* Plugin service registry
*
*
* Type-safe registry for sharing services between plugins.
*/
export class PluginServiceRegistry {
private _services = new Map<symbol, unknown>();
/**
*
* Register a service
*/
register<T>(token: ServiceToken<T>, service: T): void {
this._services.set(token.id, service);
}
/**
*
* Get a service (optional)
*/
get<T>(token: ServiceToken<T>): T | undefined {
return this._services.get(token.id) as T | undefined;
}
/**
*
* Get a service (required)
*
* @throws | If service is not registered
*/
require<T>(token: ServiceToken<T>): T {
const service = this._services.get(token.id);
if (service === undefined) {
throw new Error(`Service not found: ${token.name}`);
}
return service as T;
}
/**
*
* Check if a service is registered
*/
has<T>(token: ServiceToken<T>): boolean {
return this._services.has(token.id);
}
/**
*
* Unregister a service
*/
unregister<T>(token: ServiceToken<T>): boolean {
return this._services.delete(token.id);
}
/**
*
* Clear all services
*/
clear(): void {
this._services.clear();
}
/**
*
* Dispose resources
*
* IService
* Implements IService interface, called when service container is cleaned up.
*/
dispose(): void {
this.clear();
}
}