From 41bbe234049a101c28f12f80be4d5beea7c670e8 Mon Sep 17 00:00:00 2001 From: YHH <359807859@qq.com> Date: Fri, 10 Oct 2025 18:13:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9EServiceContainer=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=AE=B9=E5=99=A8=EF=BC=8C=20=E6=89=80=E6=9C=89?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=BB=9F=E4=B8=80=E5=AE=9E=E7=8E=B0=20IServi?= =?UTF-8?q?ce=20=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/Core.ts | 42 ++- packages/core/src/Core/ServiceContainer.ts | 334 ++++++++++++++++++ packages/core/src/ECS/Scene.ts | 9 +- packages/core/src/ECS/SceneManager.ts | 10 +- packages/core/src/ECS/Systems/EntitySystem.ts | 41 ++- packages/core/src/Utils/Debug/DebugManager.ts | 10 +- packages/core/src/Utils/PerformanceMonitor.ts | 34 +- .../core/src/Utils/Timers/TimerManager.ts | 13 +- packages/core/src/index.ts | 2 + .../core/tests/Core/ServiceContainer.test.ts | 235 ++++++++++++ .../tests/ECS/Systems/SystemTypes.test.ts | 5 + 11 files changed, 702 insertions(+), 33 deletions(-) create mode 100644 packages/core/src/Core/ServiceContainer.ts create mode 100644 packages/core/tests/Core/ServiceContainer.test.ts diff --git a/packages/core/src/Core.ts b/packages/core/src/Core.ts index 1cc4ee54..c66f7c1b 100644 --- a/packages/core/src/Core.ts +++ b/packages/core/src/Core.ts @@ -10,6 +10,7 @@ import { ICoreConfig, IECSDebugConfig } from './Types'; import { createLogger } from './Utils/Logger'; import { SceneManager } from './ECS/SceneManager'; import { IScene } from './ECS/IScene'; +import { ServiceContainer } from './Core/ServiceContainer'; /** * 游戏引擎核心类 @@ -76,6 +77,13 @@ export class Core { */ public readonly debug: boolean; + /** + * 服务容器 + * + * 管理所有服务的注册、解析和生命周期。 + */ + private _serviceContainer: ServiceContainer; + /** * 全局管理器集合 * @@ -138,23 +146,29 @@ export class Core { ...config }; + // 初始化服务容器 + this._serviceContainer = new ServiceContainer(); + // 初始化定时器管理器 this._timerManager = new TimerManager(); Core.registerGlobalManager(this._timerManager); + this._serviceContainer.registerInstance(TimerManager, this._timerManager); // 初始化性能监控器 - this._performanceMonitor = PerformanceMonitor.instance; + this._performanceMonitor = new PerformanceMonitor(); + this._serviceContainer.registerInstance(PerformanceMonitor, this._performanceMonitor); // 在调试模式下启用性能监控 if (this._config.debug) { this._performanceMonitor.enable(); } - // 初始化对象池管理器 + // 初始化对象池管理器(单例模式) this._poolManager = PoolManager.getInstance(); // 初始化场景管理器 this._sceneManager = new SceneManager(); + this._serviceContainer.registerInstance(SceneManager, this._sceneManager); Core.entitySystemsEnabled = this._config.enableEntitySystems ?? true; this.debug = this._config.debug ?? true; @@ -162,6 +176,7 @@ export class Core { // 初始化调试管理器 if (this._config.debugConfig?.enabled) { this._debugManager = new DebugManager(this, this._config.debugConfig); + this._serviceContainer.registerInstance(DebugManager, this._debugManager); } this.initialize(); @@ -176,6 +191,29 @@ export class Core { return this._instance; } + /** + * 获取服务容器 + * + * 用于注册和解析自定义服务。 + * + * @returns 服务容器实例 + * + * @example + * ```typescript + * // 注册自定义服务 + * Core.services.registerSingleton(MyService); + * + * // 解析服务 + * const myService = Core.services.resolve(MyService); + * ``` + */ + public static get services(): ServiceContainer { + if (!this._instance) { + throw new Error('Core实例未创建,请先调用Core.create()'); + } + return this._instance._serviceContainer; + } + /** * 创建Core实例 * diff --git a/packages/core/src/Core/ServiceContainer.ts b/packages/core/src/Core/ServiceContainer.ts new file mode 100644 index 00000000..9ab7652a --- /dev/null +++ b/packages/core/src/Core/ServiceContainer.ts @@ -0,0 +1,334 @@ +import { createLogger } from '../Utils/Logger'; + +const logger = createLogger('ServiceContainer'); + +/** + * 服务基础接口 + * 所有通过 ServiceContainer 管理的服务都应该实现此接口 + */ +export interface IService { + /** + * 释放服务占用的资源 + * 当服务被注销或容器被清空时调用 + */ + dispose(): void; +} + +/** + * 服务类型 + */ +export type ServiceType = new (...args: unknown[]) => T; + +/** + * 服务生命周期 + */ +export enum ServiceLifetime { + /** + * 单例模式 - 整个应用生命周期内只有一个实例 + */ + Singleton = 'singleton', + + /** + * 瞬时模式 - 每次请求都创建新实例 + */ + Transient = 'transient' +} + +/** + * 服务注册信息 + */ +interface ServiceRegistration { + /** + * 服务类型 + */ + type: ServiceType; + + /** + * 服务实例(单例模式) + */ + instance?: T; + + /** + * 工厂函数 + */ + factory?: (container: ServiceContainer) => T; + + /** + * 生命周期 + */ + lifetime: ServiceLifetime; +} + +/** + * 服务容器 + * + * 负责管理所有服务的注册、解析和生命周期。 + * 支持依赖注入和服务定位模式。 + * + * 特点: + * - 单例和瞬时两种生命周期 + * - 支持工厂函数注册 + * - 支持实例注册 + * - 类型安全的服务解析 + * + * @example + * ```typescript + * const container = new ServiceContainer(); + * + * // 注册单例服务 + * container.registerSingleton(TimerManager); + * + * // 注册工厂函数 + * container.registerSingleton(Logger, (c) => createLogger('App')); + * + * // 注册实例 + * container.registerInstance(Config, new Config()); + * + * // 解析服务 + * const timer = container.resolve(TimerManager); + * ``` + */ +export class ServiceContainer { + /** + * 服务注册表 + */ + private _services: Map, ServiceRegistration> = new Map(); + + /** + * 正在解析的服务栈(用于循环依赖检测) + */ + private _resolving: Set> = new Set(); + + /** + * 注册单例服务 + * + * @param type - 服务类型 + * @param factory - 可选的工厂函数 + * + * @example + * ```typescript + * // 直接注册类型 + * container.registerSingleton(TimerManager); + * + * // 使用工厂函数 + * container.registerSingleton(Logger, (c) => { + * return createLogger('App'); + * }); + * ``` + */ + public registerSingleton( + type: ServiceType, + factory?: (container: ServiceContainer) => T + ): void { + if (this._services.has(type as ServiceType)) { + logger.warn(`Service ${type.name} is already registered`); + return; + } + + this._services.set(type as ServiceType, { + type: type as ServiceType, + factory: factory as ((container: ServiceContainer) => IService) | undefined, + lifetime: ServiceLifetime.Singleton + }); + + logger.debug(`Registered singleton service: ${type.name}`); + } + + /** + * 注册瞬时服务 + * + * 每次解析都会创建新实例。 + * + * @param type - 服务类型 + * @param factory - 可选的工厂函数 + * + * @example + * ```typescript + * // 每次解析都创建新实例 + * container.registerTransient(Command); + * ``` + */ + public registerTransient( + type: ServiceType, + factory?: (container: ServiceContainer) => T + ): void { + if (this._services.has(type as ServiceType)) { + logger.warn(`Service ${type.name} is already registered`); + return; + } + + this._services.set(type as ServiceType, { + type: type as ServiceType, + factory: factory as ((container: ServiceContainer) => IService) | undefined, + lifetime: ServiceLifetime.Transient + }); + + logger.debug(`Registered transient service: ${type.name}`); + } + + /** + * 注册服务实例 + * + * 直接注册已创建的实例,自动视为单例。 + * + * @param type - 服务类型(构造函数,仅用作标识) + * @param instance - 服务实例 + * + * @example + * ```typescript + * const config = new Config(); + * container.registerInstance(Config, config); + * ``` + */ + public registerInstance(type: new (...args: any[]) => T, instance: T): void { + if (this._services.has(type as ServiceType)) { + logger.warn(`Service ${type.name} is already registered`); + return; + } + + this._services.set(type as ServiceType, { + type: type as ServiceType, + instance: instance as IService, + lifetime: ServiceLifetime.Singleton + }); + + logger.debug(`Registered service instance: ${type.name}`); + } + + /** + * 解析服务 + * + * @param type - 服务类型 + * @returns 服务实例 + * @throws 如果服务未注册或存在循环依赖 + * + * @example + * ```typescript + * const timer = container.resolve(TimerManager); + * ``` + */ + public resolve(type: ServiceType): T { + const registration = this._services.get(type as ServiceType); + + if (!registration) { + throw new Error(`Service ${type.name} is not registered`); + } + + // 检测循环依赖 + if (this._resolving.has(type as ServiceType)) { + const chain = Array.from(this._resolving).map(t => t.name).join(' -> '); + throw new Error(`Circular dependency detected: ${chain} -> ${type.name}`); + } + + // 如果是单例且已经有实例,直接返回 + if (registration.lifetime === ServiceLifetime.Singleton && registration.instance) { + return registration.instance as T; + } + + // 添加到解析栈 + this._resolving.add(type as ServiceType); + + try { + // 创建实例 + let instance: IService; + + if (registration.factory) { + // 使用工厂函数 + instance = registration.factory(this); + } else { + // 直接构造 + instance = new (registration.type)(); + } + + // 如果是单例,缓存实例 + if (registration.lifetime === ServiceLifetime.Singleton) { + registration.instance = instance; + } + + return instance as T; + } finally { + // 从解析栈移除 + this._resolving.delete(type as ServiceType); + } + } + + /** + * 尝试解析服务 + * + * 如果服务未注册,返回null而不是抛出异常。 + * + * @param type - 服务类型 + * @returns 服务实例或null + * + * @example + * ```typescript + * const timer = container.tryResolve(TimerManager); + * if (timer) { + * timer.schedule(...); + * } + * ``` + */ + public tryResolve(type: ServiceType): T | null { + try { + return this.resolve(type); + } catch { + return null; + } + } + + /** + * 检查服务是否已注册 + * + * @param type - 服务类型 + * @returns 是否已注册 + */ + public isRegistered(type: ServiceType): boolean { + return this._services.has(type as ServiceType); + } + + /** + * 注销服务 + * + * @param type - 服务类型 + * @returns 是否成功注销 + */ + public unregister(type: ServiceType): boolean { + const registration = this._services.get(type as ServiceType); + if (!registration) { + return false; + } + + // 如果有单例实例,调用 dispose + if (registration.instance) { + registration.instance.dispose(); + } + + this._services.delete(type as ServiceType); + logger.debug(`Unregistered service: ${type.name}`); + return true; + } + + /** + * 清空所有服务 + */ + public clear(): void { + // 清理所有单例实例 + for (const [, registration] of this._services) { + if (registration.instance) { + registration.instance.dispose(); + } + } + + this._services.clear(); + logger.debug('Cleared all services'); + } + + /** + * 获取所有已注册的服务类型 + * + * @returns 服务类型数组 + */ + public getRegisteredServices(): ServiceType[] { + return Array.from(this._services.keys()); + } +} diff --git a/packages/core/src/ECS/Scene.ts b/packages/core/src/ECS/Scene.ts index 457f0a49..0413fa92 100644 --- a/packages/core/src/ECS/Scene.ts +++ b/packages/core/src/ECS/Scene.ts @@ -13,6 +13,8 @@ import { TypedQueryBuilder } from './Core/Query/TypedQuery'; import { SceneSerializer, SceneSerializationOptions, SceneDeserializationOptions } from './Serialization/SceneSerializer'; import { IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOptions } from './Serialization/IncrementalSerializer'; import { ComponentPoolManager } from './Core/ComponentPool'; +import { PerformanceMonitor } from '../Utils/PerformanceMonitor'; +import { Core } from '../Core'; /** * 游戏场景默认实现类 @@ -423,8 +425,13 @@ export class Scene implements IScene { if (this.entityProcessors.processors.includes(processor)) { return processor; } - + processor.scene = this; + + // 从Core获取PerformanceMonitor并注入到System + const perfMonitor = Core.services.resolve(PerformanceMonitor); + processor.setPerformanceMonitor(perfMonitor); + this.entityProcessors.add(processor); processor.initialize(); processor.setUpdateOrder(this.entityProcessors.count - 1); diff --git a/packages/core/src/ECS/SceneManager.ts b/packages/core/src/ECS/SceneManager.ts index 0799c176..6f1c725d 100644 --- a/packages/core/src/ECS/SceneManager.ts +++ b/packages/core/src/ECS/SceneManager.ts @@ -3,6 +3,7 @@ import { ECSFluentAPI, createECSAPI } from './Core/FluentAPI'; import { Time } from '../Utils/Time'; import { Core } from '../Core'; import { createLogger } from '../Utils/Logger'; +import type { IService } from '../Core/ServiceContainer'; /** * 单场景管理器 @@ -46,7 +47,7 @@ import { createLogger } from '../Utils/Logger'; * sceneManager.loadScene(new MenuScene()); * ``` */ -export class SceneManager { +export class SceneManager implements IService { /** * 当前活跃场景 */ @@ -235,4 +236,11 @@ export class SceneManager { public get hasPendingScene(): boolean { return this._nextScene !== null; } + + /** + * 释放资源(IService接口) + */ + public dispose(): void { + this.destroy(); + } } diff --git a/packages/core/src/ECS/Systems/EntitySystem.ts b/packages/core/src/ECS/Systems/EntitySystem.ts index a6c607fd..25fcbf61 100644 --- a/packages/core/src/ECS/Systems/EntitySystem.ts +++ b/packages/core/src/ECS/Systems/EntitySystem.ts @@ -68,7 +68,7 @@ export abstract class EntitySystem< > implements ISystemBase { private _updateOrder: number; private _enabled: boolean; - private _performanceMonitor: PerformanceMonitor; + private _performanceMonitor: PerformanceMonitor | null; private _systemName: string; private _initialized: boolean; private _matcher: Matcher; @@ -148,7 +148,7 @@ export abstract class EntitySystem< constructor(matcher?: Matcher) { this._updateOrder = 0; this._enabled = true; - this._performanceMonitor = PerformanceMonitor.instance; + this._performanceMonitor = null; this._systemName = getSystemInstanceTypeName(this); this._initialized = false; this._matcher = matcher || Matcher.empty(); @@ -192,6 +192,23 @@ export abstract class EntitySystem< this._scene = value; } + /** + * 设置性能监控器 + */ + public setPerformanceMonitor(monitor: PerformanceMonitor): void { + this._performanceMonitor = monitor; + } + + /** + * 获取性能监控器 + */ + private getPerformanceMonitor(): PerformanceMonitor { + if (!this._performanceMonitor) { + throw new Error(`${this._systemName}: PerformanceMonitor未注入,请确保在Core.create()之后再添加System到Scene`); + } + return this._performanceMonitor; + } + /** * 获取实体匹配器 */ @@ -533,7 +550,8 @@ export abstract class EntitySystem< return; } - const startTime = this._performanceMonitor.startMonitoring(this._systemName); + const monitor = this.getPerformanceMonitor(); + const startTime = monitor.startMonitoring(this._systemName); let entityCount = 0; try { @@ -544,7 +562,7 @@ export abstract class EntitySystem< this.process(this._entityCache.frame); } finally { - this._performanceMonitor.endMonitoring(this._systemName, startTime, entityCount); + monitor.endMonitoring(this._systemName, startTime, entityCount); } } @@ -556,7 +574,8 @@ export abstract class EntitySystem< return; } - const startTime = this._performanceMonitor.startMonitoring(`${this._systemName}_Late`); + const monitor = this.getPerformanceMonitor(); + const startTime = monitor.startMonitoring(`${this._systemName}_Late`); let entityCount = 0; try { @@ -566,7 +585,7 @@ export abstract class EntitySystem< this.lateProcess(entities); this.onEnd(); } finally { - this._performanceMonitor.endMonitoring(`${this._systemName}_Late`, startTime, entityCount); + monitor.endMonitoring(`${this._systemName}_Late`, startTime, entityCount); // 清理帧缓存 this._entityCache.clearFrame(); } @@ -626,27 +645,27 @@ export abstract class EntitySystem< /** * 获取系统的性能数据 - * + * * @returns 性能数据或undefined */ public getPerformanceData() { - return this._performanceMonitor.getSystemData(this._systemName); + return this.getPerformanceMonitor().getSystemData(this._systemName); } /** * 获取系统的性能统计 - * + * * @returns 性能统计或undefined */ public getPerformanceStats() { - return this._performanceMonitor.getSystemStats(this._systemName); + return this.getPerformanceMonitor().getSystemStats(this._systemName); } /** * 重置系统的性能数据 */ public resetPerformanceData(): void { - this._performanceMonitor.resetSystem(this._systemName); + this.getPerformanceMonitor().resetSystem(this._systemName); } /** diff --git a/packages/core/src/Utils/Debug/DebugManager.ts b/packages/core/src/Utils/Debug/DebugManager.ts index 71f49f9d..6d646ff9 100644 --- a/packages/core/src/Utils/Debug/DebugManager.ts +++ b/packages/core/src/Utils/Debug/DebugManager.ts @@ -9,13 +9,14 @@ import { Component } from '../../ECS/Component'; import { ComponentPoolManager } from '../../ECS/Core/ComponentPool'; import { Pool } from '../../Utils/Pool'; import { getComponentInstanceTypeName, getSystemInstanceTypeName } from '../../ECS/Decorators'; +import type { IService } from '../../Core/ServiceContainer'; /** * 调试管理器 * * 整合所有调试数据收集器,负责收集和发送调试数据 */ -export class DebugManager { +export class DebugManager implements IService { private config: IECSDebugConfig; private webSocketManager: WebSocketManager; private entityCollector: EntityDataCollector; @@ -821,4 +822,11 @@ export class DebugManager { // console.error('[ECS Debug] 发送调试数据失败:', error); } } + + /** + * 释放资源 + */ + public dispose(): void { + this.stop(); + } } \ No newline at end of file diff --git a/packages/core/src/Utils/PerformanceMonitor.ts b/packages/core/src/Utils/PerformanceMonitor.ts index eef5644b..93286082 100644 --- a/packages/core/src/Utils/PerformanceMonitor.ts +++ b/packages/core/src/Utils/PerformanceMonitor.ts @@ -99,20 +99,20 @@ export interface PerformanceThresholds { }; } +import type { IService } from '../Core/ServiceContainer'; + /** * 高性能监控器 * 用于监控ECS系统的性能表现,提供详细的分析和优化建议 */ -export class PerformanceMonitor { - private static _instance: PerformanceMonitor; - +export class PerformanceMonitor implements IService { private _systemData = new Map(); private _systemStats = new Map(); private _warnings: PerformanceWarning[] = []; private _isEnabled = false; private _maxRecentSamples = 60; // 保留最近60帧的数据 private _maxWarnings = 100; // 最大警告数量 - + // 性能阈值配置 private _thresholds: PerformanceThresholds = { executionTime: { warning: 16.67, critical: 33.33 }, // 60fps和30fps对应的帧时间 @@ -139,18 +139,8 @@ export class PerformanceMonitor { private _gcCount = 0; private _lastGcCheck = 0; private _gcCheckInterval = 1000; - - /** - * 获取单例实例 - */ - public static get instance(): PerformanceMonitor { - if (!PerformanceMonitor._instance) { - PerformanceMonitor._instance = new PerformanceMonitor(); - } - return PerformanceMonitor._instance; - } - private constructor() {} + constructor() {} /** * 启用性能监控 @@ -392,7 +382,7 @@ export class PerformanceMonitor { */ public setMaxRecentSamples(maxSamples: number): void { this._maxRecentSamples = maxSamples; - + // 裁剪现有数据 for (const stats of this._systemStats.values()) { while (stats.recentTimes.length > maxSamples) { @@ -400,4 +390,16 @@ export class PerformanceMonitor { } } } + + /** + * 释放资源 + */ + public dispose(): void { + this._systemData.clear(); + this._systemStats.clear(); + this._warnings = []; + this._fpsHistory = []; + this._memoryHistory = []; + this._isEnabled = false; + } } \ No newline at end of file diff --git a/packages/core/src/Utils/Timers/TimerManager.ts b/packages/core/src/Utils/Timers/TimerManager.ts index 44a2733f..c8fe73e8 100644 --- a/packages/core/src/Utils/Timers/TimerManager.ts +++ b/packages/core/src/Utils/Timers/TimerManager.ts @@ -1,11 +1,12 @@ import { GlobalManager } from '../GlobalManager'; import { Timer } from './Timer'; import { ITimer } from './ITimer'; +import type { IService } from '../../Core/ServiceContainer'; /** * 允许动作的延迟和重复执行 */ -export class TimerManager extends GlobalManager { +export class TimerManager extends GlobalManager implements IService { public _timers: Array> = []; public override update() { @@ -31,4 +32,14 @@ export class TimerManager extends GlobalManager { return timer; } + + /** + * 释放资源 + */ + public dispose(): void { + for (const timer of this._timers) { + timer.unload(); + } + this._timers = []; + } } \ No newline at end of file diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index feb1e347..c75b0496 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -5,6 +5,8 @@ // 核心模块 export { Core } from './Core'; +export { ServiceContainer, ServiceLifetime } from './Core/ServiceContainer'; +export type { IService, ServiceType } from './Core/ServiceContainer'; // 核心管理器 export { Emitter, FuncPack } from './Utils/Emitter'; diff --git a/packages/core/tests/Core/ServiceContainer.test.ts b/packages/core/tests/Core/ServiceContainer.test.ts new file mode 100644 index 00000000..3595243b --- /dev/null +++ b/packages/core/tests/Core/ServiceContainer.test.ts @@ -0,0 +1,235 @@ +import { ServiceContainer, ServiceLifetime } from '../../src/Core/ServiceContainer'; + +// 测试服务类 +class TestService { + public value: number = 0; + + constructor() { + this.value = Math.random(); + } + + dispose() { + // 清理资源 + } +} + +class DependentService { + public testService?: TestService; + + constructor(...args: unknown[]) { + this.testService = args[0] as TestService | undefined; + } + + dispose() { + // 清理资源 + } +} + +class DisposableService { + public disposed = false; + + dispose() { + this.disposed = true; + } +} + +describe('ServiceContainer - 服务容器测试', () => { + let container: ServiceContainer; + + beforeEach(() => { + container = new ServiceContainer(); + }); + + describe('单例服务注册', () => { + test('应该能够注册单例服务', () => { + container.registerSingleton(TestService); + expect(container.isRegistered(TestService)).toBe(true); + }); + + test('单例服务应该返回相同实例', () => { + container.registerSingleton(TestService); + + const instance1 = container.resolve(TestService); + const instance2 = container.resolve(TestService); + + expect(instance1).toBe(instance2); + expect(instance1.value).toBe(instance2.value); + }); + + test('应该能够使用工厂函数注册单例', () => { + const fixedValue = 42; + container.registerSingleton(TestService, () => { + const service = new TestService(); + service.value = fixedValue; + return service; + }); + + const instance = container.resolve(TestService); + expect(instance.value).toBe(fixedValue); + }); + }); + + describe('瞬时服务注册', () => { + test('应该能够注册瞬时服务', () => { + container.registerTransient(TestService); + expect(container.isRegistered(TestService)).toBe(true); + }); + + test('瞬时服务应该每次返回新实例', () => { + container.registerTransient(TestService); + + const instance1 = container.resolve(TestService); + const instance2 = container.resolve(TestService); + + expect(instance1).not.toBe(instance2); + expect(instance1.value).not.toBe(instance2.value); + }); + }); + + describe('实例注册', () => { + test('应该能够注册已存在的实例', () => { + const instance = new TestService(); + instance.value = 99; + + container.registerInstance(TestService, instance); + + const resolved = container.resolve(TestService); + expect(resolved).toBe(instance); + expect(resolved.value).toBe(99); + }); + }); + + describe('服务解析', () => { + test('解析未注册的服务应该抛出错误', () => { + expect(() => container.resolve(TestService)).toThrow( + 'Service TestService is not registered' + ); + }); + + test('tryResolve应该返回null而不是抛出错误', () => { + const result = container.tryResolve(TestService); + expect(result).toBeNull(); + }); + + test('tryResolve应该返回已注册的服务', () => { + container.registerSingleton(TestService); + const result = container.tryResolve(TestService); + expect(result).not.toBeNull(); + expect(result).toBeInstanceOf(TestService); + }); + }); + + describe('依赖注入', () => { + test('工厂函数应该能够解析其他服务', () => { + container.registerSingleton(TestService); + container.registerSingleton(DependentService, (c) => { + const testService = c.resolve(TestService); + return new DependentService(testService); + }); + + const dependent = container.resolve(DependentService); + const test = container.resolve(TestService); + + expect(dependent.testService).toBe(test); + }); + }); + + describe('循环依赖检测', () => { + test('应该检测并报告循环依赖', () => { + class ServiceA { + constructor() { + // 在构造函数中尝试解析ServiceB会导致循环依赖 + } + dispose() {} + } + + class ServiceB { + constructor() {} + dispose() {} + } + + container.registerSingleton(ServiceA, (c) => { + c.resolve(ServiceB); // 尝试解析B + return new ServiceA(); + }); + + container.registerSingleton(ServiceB, (c) => { + c.resolve(ServiceA); // 尝试解析A + return new ServiceB(); + }); + + expect(() => container.resolve(ServiceA)).toThrow(/Circular dependency detected/); + }); + }); + + describe('服务注销', () => { + test('应该能够注销服务', () => { + container.registerSingleton(TestService); + expect(container.isRegistered(TestService)).toBe(true); + + const result = container.unregister(TestService); + expect(result).toBe(true); + expect(container.isRegistered(TestService)).toBe(false); + }); + + test('注销不存在的服务应该返回false', () => { + const result = container.unregister(TestService); + expect(result).toBe(false); + }); + + test('注销服务应该调用dispose方法', () => { + const instance = new DisposableService(); + container.registerInstance(DisposableService, instance); + + container.unregister(DisposableService); + expect(instance.disposed).toBe(true); + }); + }); + + describe('清空容器', () => { + test('应该能够清空所有服务', () => { + container.registerSingleton(TestService); + container.registerTransient(DependentService); + + expect(container.getRegisteredServices().length).toBe(2); + + container.clear(); + + expect(container.getRegisteredServices().length).toBe(0); + }); + + test('清空容器应该调用所有单例的dispose方法', () => { + const instance = new DisposableService(); + container.registerInstance(DisposableService, instance); + + container.clear(); + expect(instance.disposed).toBe(true); + }); + }); + + describe('重复注册', () => { + test('重复注册应该发出警告但不覆盖', () => { + container.registerSingleton(TestService); + const instance1 = container.resolve(TestService); + + // 尝试重复注册 + container.registerSingleton(TestService); + const instance2 = container.resolve(TestService); + + // 应该返回相同的实例(没有被覆盖) + expect(instance1).toBe(instance2); + }); + }); + + describe('获取已注册服务列表', () => { + test('应该返回所有已注册的服务类型', () => { + container.registerSingleton(TestService); + container.registerTransient(DependentService); + + const services = container.getRegisteredServices(); + expect(services).toContain(TestService); + expect(services).toContain(DependentService); + expect(services.length).toBe(2); + }); + }); +}); diff --git a/packages/core/tests/ECS/Systems/SystemTypes.test.ts b/packages/core/tests/ECS/Systems/SystemTypes.test.ts index 94c815ce..0a5bae73 100644 --- a/packages/core/tests/ECS/Systems/SystemTypes.test.ts +++ b/packages/core/tests/ECS/Systems/SystemTypes.test.ts @@ -7,6 +7,7 @@ import { Component } from '../../../src/ECS/Component'; import { ComponentRegistry } from '../../../src/ECS/Core/ComponentStorage'; import { Time } from '../../../src/Utils/Time'; import { Matcher } from '../../../src/ECS/Utils/Matcher'; +import { Core } from '../../../src/Core'; // 测试组件 class TestComponent extends Component { @@ -83,6 +84,7 @@ describe('System Types - 系统类型测试', () => { let entity: Entity; beforeEach(() => { + Core.create(); scene = new Scene(); entity = scene.createEntity('TestEntity'); // 重置时间系统 @@ -97,6 +99,7 @@ describe('System Types - 系统类型测试', () => { beforeEach(() => { passiveSystem = new ConcretePassiveSystem(); + scene.addEntityProcessor(passiveSystem); }); test('应该能够创建被动系统', () => { @@ -136,6 +139,7 @@ describe('System Types - 系统类型测试', () => { beforeEach(() => { intervalSystem = new ConcreteIntervalSystem(testInterval); + scene.addEntityProcessor(intervalSystem); }); test('应该能够创建间隔系统', () => { @@ -218,6 +222,7 @@ describe('System Types - 系统类型测试', () => { beforeEach(() => { processingSystem = new ConcreteProcessingSystem(); + scene.addEntityProcessor(processingSystem); }); test('应该能够创建处理系统', () => {