mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
refactor(architecture): 简化模块注册接口并增强配置管理
- 移除 RegisterBuiltInModules 方法中的 ArchitectureProperties 参数 - 更新 ArchitectureModuleRegistry 使用 ConcurrentDictionary 存储模块工厂 - 实现模块注册的幂等性检查,相同模块名只注册一次 - 为 ArchEcsModule 添加 ArchOptions 配置类支持 - 更新 UseArch 扩展方法传递配置选项给 ArchEcsModule - 移除废弃的 properties 命名空间引用 - 添加显式注册集成测试验证模块配置功能
This commit is contained in:
parent
ac2a9759e1
commit
5c5525e3e9
@ -1,3 +1,5 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace GFramework.Core.Abstractions.architecture;
|
||||
|
||||
/// <summary>
|
||||
@ -5,15 +7,20 @@ namespace GFramework.Core.Abstractions.architecture;
|
||||
/// </summary>
|
||||
public static class ArchitectureModuleRegistry
|
||||
{
|
||||
private static readonly List<Func<IServiceModule>> _factories = [];
|
||||
private static readonly ConcurrentDictionary<string, Func<IServiceModule>> _factories = new();
|
||||
|
||||
/// <summary>
|
||||
/// 注册模块工厂
|
||||
/// 注册模块工厂(幂等操作,相同模块名只会注册一次)
|
||||
/// </summary>
|
||||
/// <param name="factory">模块工厂函数</param>
|
||||
public static void Register(Func<IServiceModule> factory)
|
||||
{
|
||||
_factories.Add(factory);
|
||||
// 创建临时实例以获取模块名(用于幂等性检查)
|
||||
var tempModule = factory();
|
||||
var moduleName = tempModule.ModuleName;
|
||||
|
||||
// 幂等注册:相同模块名只注册一次
|
||||
_factories.TryAdd(moduleName, factory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -22,7 +29,7 @@ public static class ArchitectureModuleRegistry
|
||||
/// <returns>模块实例集合</returns>
|
||||
public static IEnumerable<IServiceModule> CreateModules()
|
||||
{
|
||||
return _factories.Select(f => f());
|
||||
return _factories.Values.Select(f => f());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using GFramework.Core.Abstractions.ioc;
|
||||
using GFramework.Core.Abstractions.properties;
|
||||
|
||||
namespace GFramework.Core.Abstractions.architecture;
|
||||
|
||||
@ -18,8 +17,7 @@ public interface IServiceModuleManager
|
||||
/// 注册内置的服务模块。
|
||||
/// </summary>
|
||||
/// <param name="container">IoC容器实例,用于解析依赖。</param>
|
||||
/// <param name="properties">架构属性配置,用于模块初始化。</param>
|
||||
void RegisterBuiltInModules(IIocContainer container, ArchitectureProperties properties);
|
||||
void RegisterBuiltInModules(IIocContainer container);
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有已注册的服务模块。
|
||||
|
||||
@ -4,7 +4,6 @@ using GFramework.Core.Abstractions.environment;
|
||||
using GFramework.Core.Abstractions.events;
|
||||
using GFramework.Core.Abstractions.ioc;
|
||||
using GFramework.Core.Abstractions.model;
|
||||
using GFramework.Core.Abstractions.properties;
|
||||
using GFramework.Core.Abstractions.query;
|
||||
using GFramework.Core.Abstractions.system;
|
||||
using GFramework.Core.Abstractions.utility;
|
||||
@ -47,8 +46,7 @@ public class ArchitectureServicesTests
|
||||
|
||||
private void RegisterBuiltInServices()
|
||||
{
|
||||
var properties = new ArchitectureProperties();
|
||||
_services!.ModuleManager.RegisterBuiltInModules(_services.Container, properties);
|
||||
_services!.ModuleManager.RegisterBuiltInModules(_services.Container);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -215,13 +213,11 @@ public class ArchitectureServicesTests
|
||||
[Test]
|
||||
public void Multiple_Instances_Should_Have_Independent_EventBus()
|
||||
{
|
||||
var properties = new ArchitectureProperties();
|
||||
|
||||
var services1 = new ArchitectureServices();
|
||||
services1.ModuleManager.RegisterBuiltInModules(services1.Container, properties);
|
||||
services1.ModuleManager.RegisterBuiltInModules(services1.Container);
|
||||
|
||||
var services2 = new ArchitectureServices();
|
||||
services2.ModuleManager.RegisterBuiltInModules(services2.Container, properties);
|
||||
services2.ModuleManager.RegisterBuiltInModules(services2.Container);
|
||||
|
||||
Assert.That(services1.EventBus, Is.Not.SameAs(services2.EventBus));
|
||||
}
|
||||
@ -232,13 +228,11 @@ public class ArchitectureServicesTests
|
||||
[Test]
|
||||
public void Multiple_Instances_Should_Have_Independent_CommandBus()
|
||||
{
|
||||
var properties = new ArchitectureProperties();
|
||||
|
||||
var services1 = new ArchitectureServices();
|
||||
services1.ModuleManager.RegisterBuiltInModules(services1.Container, properties);
|
||||
services1.ModuleManager.RegisterBuiltInModules(services1.Container);
|
||||
|
||||
var services2 = new ArchitectureServices();
|
||||
services2.ModuleManager.RegisterBuiltInModules(services2.Container, properties);
|
||||
services2.ModuleManager.RegisterBuiltInModules(services2.Container);
|
||||
|
||||
Assert.That(services1.CommandExecutor, Is.Not.SameAs(services2.CommandExecutor));
|
||||
}
|
||||
@ -249,13 +243,11 @@ public class ArchitectureServicesTests
|
||||
[Test]
|
||||
public void Multiple_Instances_Should_Have_Independent_QueryBus()
|
||||
{
|
||||
var properties = new ArchitectureProperties();
|
||||
|
||||
var services1 = new ArchitectureServices();
|
||||
services1.ModuleManager.RegisterBuiltInModules(services1.Container, properties);
|
||||
services1.ModuleManager.RegisterBuiltInModules(services1.Container);
|
||||
|
||||
var services2 = new ArchitectureServices();
|
||||
services2.ModuleManager.RegisterBuiltInModules(services2.Container, properties);
|
||||
services2.ModuleManager.RegisterBuiltInModules(services2.Container);
|
||||
|
||||
Assert.That(services1.QueryExecutor, Is.Not.SameAs(services2.QueryExecutor));
|
||||
}
|
||||
|
||||
@ -641,8 +641,8 @@ public abstract class Architecture(
|
||||
_logger = LoggerFactoryResolver.Provider.CreateLogger(GetType().Name);
|
||||
Environment.Initialize();
|
||||
|
||||
// 注册内置服务模块(根据配置)
|
||||
Services.ModuleManager.RegisterBuiltInModules(Container, Configuration.ArchitectureProperties);
|
||||
// 注册内置服务模块
|
||||
Services.ModuleManager.RegisterBuiltInModules(Container);
|
||||
|
||||
// 将 Environment 注册到容器(如果尚未注册)
|
||||
if (!Container.Contains<IEnvironment>())
|
||||
|
||||
@ -2,7 +2,6 @@ using GFramework.Core.Abstractions.architecture;
|
||||
using GFramework.Core.Abstractions.ioc;
|
||||
using GFramework.Core.Abstractions.lifecycle;
|
||||
using GFramework.Core.Abstractions.logging;
|
||||
using GFramework.Core.Abstractions.properties;
|
||||
using GFramework.Core.logging;
|
||||
using GFramework.Core.services.modules;
|
||||
|
||||
@ -44,11 +43,10 @@ public sealed class ServiceModuleManager : IServiceModuleManager
|
||||
/// <summary>
|
||||
/// 注册内置服务模块,并根据优先级排序后完成服务注册。
|
||||
/// 内置模块包括事件总线、命令执行器、查询执行器等核心模块。
|
||||
/// 同时注册通过 ModuleInitializer 自动注册的外部模块。
|
||||
/// 同时注册通过 ArchitectureModuleRegistry 自动注册的外部模块。
|
||||
/// </summary>
|
||||
/// <param name="container">IoC容器实例,用于模块服务注册。</param>
|
||||
/// <param name="properties">架构属性配置。</param>
|
||||
public void RegisterBuiltInModules(IIocContainer container, ArchitectureProperties properties)
|
||||
public void RegisterBuiltInModules(IIocContainer container)
|
||||
{
|
||||
if (_builtInModulesRegistered)
|
||||
{
|
||||
@ -62,7 +60,7 @@ public sealed class ServiceModuleManager : IServiceModuleManager
|
||||
RegisterModule(new QueryExecutorModule());
|
||||
RegisterModule(new AsyncQueryExecutorModule());
|
||||
|
||||
// 注册外部模块(通过 ModuleInitializer 自动注册)
|
||||
// 注册外部模块(通过 ArchitectureModuleRegistry 自动注册)
|
||||
foreach (var module in ArchitectureModuleRegistry.CreateModules())
|
||||
{
|
||||
RegisterModule(module);
|
||||
|
||||
@ -0,0 +1,135 @@
|
||||
using Arch.Core;
|
||||
using GFramework.Core.Abstractions.architecture;
|
||||
using GFramework.Core.architecture;
|
||||
using GFramework.Core.ioc;
|
||||
using GFramework.Ecs.Arch.Abstractions;
|
||||
using GFramework.Ecs.Arch.extensions;
|
||||
|
||||
namespace GFramework.Ecs.Arch.Tests.integration;
|
||||
|
||||
/// <summary>
|
||||
/// 显式注册集成测试
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class ExplicitRegistrationTests
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_container = new MicrosoftDiContainer();
|
||||
_context = new ArchitectureContext(_container);
|
||||
|
||||
// 清空注册表,确保测试隔离
|
||||
ArchitectureModuleRegistry.Clear();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
_container?.Clear();
|
||||
_context = null;
|
||||
ArchitectureModuleRegistry.Clear();
|
||||
GameContext.Clear();
|
||||
}
|
||||
|
||||
private MicrosoftDiContainer? _container;
|
||||
private ArchitectureContext? _context;
|
||||
|
||||
/// <summary>
|
||||
/// 测试 Arch ECS 模块显式注册
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ArchEcsModule_Should_Be_Explicitly_Registered()
|
||||
{
|
||||
// Arrange
|
||||
var architecture = new TestArchitecture();
|
||||
|
||||
// Act - 显式注册
|
||||
architecture.UseArch();
|
||||
architecture.Initialize();
|
||||
|
||||
// Assert - 验证 World 已注册(由 ArchEcsModule 注册)
|
||||
var world = architecture.Context.GetService<World>();
|
||||
Assert.That(world, Is.Not.Null, "World should be registered by ArchEcsModule");
|
||||
|
||||
// 验证 IArchEcsModule 已注册
|
||||
var ecsModule = architecture.Context.GetService<IArchEcsModule>();
|
||||
Assert.That(ecsModule, Is.Not.Null, "IArchEcsModule should be registered");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 World 是否正确注册到容器
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void World_Should_Be_Registered_In_Container()
|
||||
{
|
||||
// Arrange
|
||||
var architecture = new TestArchitecture();
|
||||
|
||||
// Act - 显式注册
|
||||
architecture.UseArch();
|
||||
architecture.Initialize();
|
||||
|
||||
// Assert
|
||||
var world = architecture.Context.GetService<World>();
|
||||
Assert.That(world, Is.Not.Null, "World should be registered in container");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试带配置的注册
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void UseArch_Should_Accept_Configuration()
|
||||
{
|
||||
// Arrange
|
||||
var architecture = new TestArchitecture();
|
||||
var configCalled = false;
|
||||
|
||||
// Act
|
||||
architecture.UseArch(options =>
|
||||
{
|
||||
options.WorldCapacity = 2000;
|
||||
options.EnableStatistics = true;
|
||||
configCalled = true;
|
||||
});
|
||||
|
||||
// Assert
|
||||
Assert.That(configCalled, Is.True, "Configuration delegate should be called");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试链式调用
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void UseArch_Should_Support_Chaining()
|
||||
{
|
||||
// Arrange & Act
|
||||
var architecture = new TestArchitecture()
|
||||
.UseArch()
|
||||
.UseArch(options => options.WorldCapacity = 2000);
|
||||
|
||||
architecture.Initialize();
|
||||
|
||||
// Assert - 验证模块已注册
|
||||
var world = architecture.Context.GetService<World>();
|
||||
Assert.That(world, Is.Not.Null, "World should be registered");
|
||||
|
||||
var ecsModule = architecture.Context.GetService<IArchEcsModule>();
|
||||
Assert.That(ecsModule, Is.Not.Null, "IArchEcsModule should be registered");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试架构类,用于测试
|
||||
/// </summary>
|
||||
private class TestArchitecture : Architecture
|
||||
{
|
||||
public TestArchitecture() : base(new ArchitectureConfiguration())
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
// 测试架构,无需额外初始化
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,7 @@ namespace GFramework.Ecs.Arch;
|
||||
/// </summary>
|
||||
public sealed class ArchEcsModule : IArchEcsModule
|
||||
{
|
||||
private readonly ArchOptions _options;
|
||||
private IIocContainer? _container;
|
||||
private bool _isInitialized;
|
||||
private IReadOnlyList<ArchSystemAdapter<float>> _systems = [];
|
||||
@ -16,9 +17,11 @@ public sealed class ArchEcsModule : IArchEcsModule
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="options">配置选项</param>
|
||||
/// <param name="enabled">是否启用模块</param>
|
||||
public ArchEcsModule(bool enabled = true)
|
||||
public ArchEcsModule(ArchOptions? options = null, bool enabled = true)
|
||||
{
|
||||
_options = options ?? new ArchOptions();
|
||||
IsEnabled = enabled;
|
||||
}
|
||||
|
||||
@ -30,7 +33,7 @@ public sealed class ArchEcsModule : IArchEcsModule
|
||||
/// <summary>
|
||||
/// 模块优先级
|
||||
/// </summary>
|
||||
public int Priority => 50;
|
||||
public int Priority => _options.Priority;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用
|
||||
@ -49,8 +52,8 @@ public sealed class ArchEcsModule : IArchEcsModule
|
||||
// 注册模块自身
|
||||
container.RegisterPlurality(this);
|
||||
|
||||
// 创建并注册 World
|
||||
_world = World.Create();
|
||||
// 创建并注册 World(使用配置的容量)
|
||||
_world = World.Create(_options.WorldCapacity);
|
||||
container.Register(_world);
|
||||
}
|
||||
|
||||
|
||||
22
GFramework.Ecs.Arch/ArchOptions.cs
Normal file
22
GFramework.Ecs.Arch/ArchOptions.cs
Normal file
@ -0,0 +1,22 @@
|
||||
namespace GFramework.Ecs.Arch;
|
||||
|
||||
/// <summary>
|
||||
/// Arch ECS 模块配置选项
|
||||
/// </summary>
|
||||
public sealed class ArchOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// World 初始容量(默认:1000)
|
||||
/// </summary>
|
||||
public int WorldCapacity { get; set; } = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用统计信息(默认:false)
|
||||
/// </summary>
|
||||
public bool EnableStatistics { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 模块优先级(默认:50)
|
||||
/// </summary>
|
||||
public int Priority { get; set; } = 50;
|
||||
}
|
||||
@ -23,8 +23,8 @@ public static class ArchExtensions
|
||||
var options = new ArchOptions();
|
||||
configure?.Invoke(options);
|
||||
|
||||
// 注册模块
|
||||
ArchitectureModuleRegistry.Register(() => new ArchEcsModule(enabled: true));
|
||||
// 注册模块(传递配置选项)
|
||||
ArchitectureModuleRegistry.Register(() => new ArchEcsModule(options, enabled: true));
|
||||
|
||||
return architecture;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user