diff --git a/GFramework.Core.Abstractions/architecture/IArchitectureContext.cs b/GFramework.Core.Abstractions/architecture/IArchitectureContext.cs index 91fa53b..6f4ba1e 100644 --- a/GFramework.Core.Abstractions/architecture/IArchitectureContext.cs +++ b/GFramework.Core.Abstractions/architecture/IArchitectureContext.cs @@ -15,6 +15,13 @@ namespace GFramework.Core.Abstractions.architecture; /// public interface IArchitectureContext { + /// + /// 获取指定类型的服务实例 + /// + /// 服务类型 + /// 服务实例,如果不存在则返回null + TService? GetService() where TService : class; + /// /// 获取指定类型的系统实例 /// diff --git a/GFramework.Core.Tests/architecture/ArchitectureContextTests.cs b/GFramework.Core.Tests/architecture/ArchitectureContextTests.cs index 082a2ff..da2ed5f 100644 --- a/GFramework.Core.Tests/architecture/ArchitectureContextTests.cs +++ b/GFramework.Core.Tests/architecture/ArchitectureContextTests.cs @@ -57,12 +57,21 @@ public class ArchitectureContextTests loggerField?.SetValue(_container, LoggerFactoryResolver.Provider.CreateLogger(nameof(ArchitectureContextTests))); + // 创建服务实例 _eventBus = new EventBus(); _commandBus = new CommandBus(); _queryBus = new QueryBus(); _asyncQueryBus = new AsyncQueryBus(); _environment = new DefaultEnvironment(); - _context = new ArchitectureContext(_container, _eventBus, _commandBus, _queryBus, _environment, _asyncQueryBus); + + // 将服务注册到容器 + _container.RegisterPlurality(_eventBus); + _container.RegisterPlurality(_commandBus); + _container.RegisterPlurality(_queryBus); + _container.RegisterPlurality(_asyncQueryBus); + _container.RegisterPlurality(_environment); + + _context = new ArchitectureContext(_container); } private ArchitectureContext? _context; @@ -79,10 +88,7 @@ public class ArchitectureContextTests [Test] public void Constructor_Should_NotThrow_When_AllParameters_AreValid() { - Assert.That( - () => new ArchitectureContext(_container!, _eventBus!, _commandBus!, _queryBus!, _environment!, - _asyncQueryBus!), - Throws.Nothing); + Assert.That(() => new ArchitectureContext(_container!), Throws.Nothing); } /// @@ -91,53 +97,7 @@ public class ArchitectureContextTests [Test] public void Constructor_Should_Throw_When_Container_IsNull() { - Assert.That( - () => new ArchitectureContext(null!, _eventBus!, _commandBus!, _queryBus!, _environment!, _asyncQueryBus!), - Throws.ArgumentNullException); - } - - /// - /// 测试构造函数在 eventBus 为 null 时应抛出 ArgumentNullException - /// - [Test] - public void Constructor_Should_Throw_When_EventBus_IsNull() - { - Assert.That( - () => new ArchitectureContext(_container!, null!, _commandBus!, _queryBus!, _environment!, _asyncQueryBus!), - Throws.ArgumentNullException); - } - - /// - /// 测试构造函数在 commandBus 为 null 时应抛出 ArgumentNullException - /// - [Test] - public void Constructor_Should_Throw_When_CommandBus_IsNull() - { - Assert.That( - () => new ArchitectureContext(_container!, _eventBus!, null!, _queryBus!, _environment!, _asyncQueryBus!), - Throws.ArgumentNullException); - } - - /// - /// 测试构造函数在 queryBus 为 null 时应抛出 ArgumentNullException - /// - [Test] - public void Constructor_Should_Throw_When_QueryBus_IsNull() - { - Assert.That( - () => new ArchitectureContext(_container!, _eventBus!, _commandBus!, null!, _environment!, _asyncQueryBus!), - Throws.ArgumentNullException); - } - - /// - /// 测试构造函数在 environment 为 null 时应抛出 ArgumentNullException - /// - [Test] - public void Constructor_Should_Throw_When_Environment_IsNull() - { - Assert.That( - () => new ArchitectureContext(_container!, _eventBus!, _commandBus!, _queryBus!, null!, _asyncQueryBus!), - Throws.ArgumentNullException); + Assert.That(() => new ArchitectureContext(null!), Throws.ArgumentNullException); } /// @@ -146,55 +106,10 @@ public class ArchitectureContextTests [Test] public void Constructor_Should_ThrowArgumentNullException_When_Container_IsNull() { - Assert.That( - () => new ArchitectureContext(null!, _eventBus!, _commandBus!, _queryBus!, _environment!, _asyncQueryBus!), + Assert.That(() => new ArchitectureContext(null!), Throws.ArgumentNullException.With.Property("ParamName").EqualTo("container")); } - /// - /// 测试构造函数在EventBus为null时应抛出ArgumentNullException - /// - [Test] - public void Constructor_Should_ThrowArgumentNullException_When_EventBus_IsNull() - { - Assert.That( - () => new ArchitectureContext(_container!, null!, _commandBus!, _queryBus!, _environment!, _asyncQueryBus!), - Throws.ArgumentNullException.With.Property("ParamName").EqualTo("eventBus")); - } - - /// - /// 测试构造函数在CommandBus为null时应抛出ArgumentNullException - /// - [Test] - public void Constructor_Should_ThrowArgumentNullException_When_CommandBus_IsNull() - { - Assert.That( - () => new ArchitectureContext(_container!, _eventBus!, null!, _queryBus!, _environment!, _asyncQueryBus!), - Throws.ArgumentNullException.With.Property("ParamName").EqualTo("commandBus")); - } - - /// - /// 测试构造函数在QueryBus为null时应抛出ArgumentNullException - /// - [Test] - public void Constructor_Should_ThrowArgumentNullException_When_QueryBus_IsNull() - { - Assert.That( - () => new ArchitectureContext(_container!, _eventBus!, _commandBus!, null!, _environment!, _asyncQueryBus!), - Throws.ArgumentNullException.With.Property("ParamName").EqualTo("queryBus")); - } - - /// - /// 测试构造函数在Environment为null时应抛出ArgumentNullException - /// - [Test] - public void Constructor_Should_ThrowArgumentNullException_When_Environment_IsNull() - { - Assert.That( - () => new ArchitectureContext(_container!, _eventBus!, _commandBus!, _queryBus!, null!, _asyncQueryBus!), - Throws.ArgumentNullException.With.Property("ParamName").EqualTo("environment")); - } - /// /// 测试SendQuery方法在查询有效时返回正确结果 /// @@ -439,14 +354,6 @@ public class TestUtilityV2 : IUtility public void SetContext(IArchitectureContext context) => _context = context; public IArchitectureContext GetContext() => _context; - - public void Init() - { - } - - public void Destroy() - { - } } public class TestQueryV2 : IQuery diff --git a/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs b/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs index 9459b36..fb1e7bb 100644 --- a/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs +++ b/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs @@ -227,6 +227,7 @@ public class TestArchitectureContextV3 : IArchitectureContext public ICommandBus CommandBus => new CommandBus(); public IQueryBus QueryBus => new QueryBus(); + public TService? GetService() where TService : class => _container.Get(); public TModel? GetModel() where TModel : class, IModel => _container.Get(); public TSystem? GetSystem() where TSystem : class, ISystem => _container.Get(); public TUtility? GetUtility() where TUtility : class, IUtility => _container.Get(); diff --git a/GFramework.Core.Tests/architecture/GameContextTests.cs b/GFramework.Core.Tests/architecture/GameContextTests.cs index a99ede0..588830e 100644 --- a/GFramework.Core.Tests/architecture/GameContextTests.cs +++ b/GFramework.Core.Tests/architecture/GameContextTests.cs @@ -256,6 +256,13 @@ public class TestArchitectureContext : IArchitectureContext /// public IEnvironment Environment => new DefaultEnvironment(); + /// + /// 获取指定类型的服务 + /// + /// 服务类型 + /// 服务实例或null + public TService? GetService() where TService : class => _container.Get(); + /// /// 获取指定类型的模型 /// diff --git a/GFramework.Core.Tests/command/AbstractAsyncCommandTests.cs b/GFramework.Core.Tests/command/AbstractAsyncCommandTests.cs index b831c0d..cedd3fc 100644 --- a/GFramework.Core.Tests/command/AbstractAsyncCommandTests.cs +++ b/GFramework.Core.Tests/command/AbstractAsyncCommandTests.cs @@ -33,13 +33,12 @@ public class AbstractAsyncCommandTests public void SetUp() { _container = new IocContainer(); - _context = new ArchitectureContext( - _container, - new EventBus(), - new CommandBus(), - new QueryBus(), - new DefaultEnvironment(), - new AsyncQueryBus()); + _container.RegisterPlurality(new EventBus()); + _container.RegisterPlurality(new CommandBus()); + _container.RegisterPlurality(new QueryBus()); + _container.RegisterPlurality(new DefaultEnvironment()); + _container.RegisterPlurality(new AsyncQueryBus()); + _context = new ArchitectureContext(_container); } private ArchitectureContext _context = null!; diff --git a/GFramework.Core.Tests/query/AbstractAsyncQueryTests.cs b/GFramework.Core.Tests/query/AbstractAsyncQueryTests.cs index cb4ce24..b165954 100644 --- a/GFramework.Core.Tests/query/AbstractAsyncQueryTests.cs +++ b/GFramework.Core.Tests/query/AbstractAsyncQueryTests.cs @@ -31,13 +31,12 @@ public class AbstractAsyncQueryTests public void SetUp() { _container = new IocContainer(); - _context = new ArchitectureContext( - _container, - new EventBus(), - new CommandBus(), - new QueryBus(), - new DefaultEnvironment(), - new AsyncQueryBus()); + _container.RegisterPlurality(new EventBus()); + _container.RegisterPlurality(new CommandBus()); + _container.RegisterPlurality(new QueryBus()); + _container.RegisterPlurality(new DefaultEnvironment()); + _container.RegisterPlurality(new AsyncQueryBus()); + _context = new ArchitectureContext(_container); } private ArchitectureContext _context = null!; diff --git a/GFramework.Core.Tests/state/StateMachineSystemTests.cs b/GFramework.Core.Tests/state/StateMachineSystemTests.cs index 0ca3db0..631cf13 100644 --- a/GFramework.Core.Tests/state/StateMachineSystemTests.cs +++ b/GFramework.Core.Tests/state/StateMachineSystemTests.cs @@ -1,3 +1,4 @@ +using System.Reflection; using GFramework.Core.Abstractions.enums; using GFramework.Core.Abstractions.state; using GFramework.Core.Abstractions.system; @@ -6,6 +7,7 @@ using GFramework.Core.command; using GFramework.Core.environment; using GFramework.Core.events; using GFramework.Core.ioc; +using GFramework.Core.logging; using GFramework.Core.query; using GFramework.Core.state; using NUnit.Framework; @@ -35,14 +37,25 @@ public class StateMachineSystemTests [SetUp] public void SetUp() { + // 初始化 LoggerFactoryResolver 以支持 IocContainer + LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider(); + _eventBus = new EventBus(); - _context = new ArchitectureContext( - new IocContainer(), - _eventBus, - new CommandBus(), - new QueryBus(), - new DefaultEnvironment(), - new AsyncQueryBus()); + var container = new IocContainer(); + + // 直接初始化 logger 字段 + var loggerField = typeof(IocContainer).GetField("_logger", + BindingFlags.NonPublic | BindingFlags.Instance); + loggerField?.SetValue(container, + LoggerFactoryResolver.Provider.CreateLogger(nameof(StateMachineSystemTests))); + + container.RegisterPlurality(_eventBus); + container.RegisterPlurality(new CommandBus()); + container.RegisterPlurality(new QueryBus()); + container.RegisterPlurality(new DefaultEnvironment()); + container.RegisterPlurality(new AsyncQueryBus()); + + _context = new ArchitectureContext(container); _stateMachine = new TestStateMachineSystemV5(); _stateMachine.SetContext(_context); diff --git a/GFramework.Core.Tests/utility/AbstractContextUtilityTests.cs b/GFramework.Core.Tests/utility/AbstractContextUtilityTests.cs index 0ce990a..befe58a 100644 --- a/GFramework.Core.Tests/utility/AbstractContextUtilityTests.cs +++ b/GFramework.Core.Tests/utility/AbstractContextUtilityTests.cs @@ -31,13 +31,12 @@ public class AbstractContextUtilityTests public void SetUp() { _container = new IocContainer(); - _context = new ArchitectureContext( - _container, - new EventBus(), - new CommandBus(), - new QueryBus(), - new DefaultEnvironment(), - new AsyncQueryBus()); + _container.RegisterPlurality(new EventBus()); + _container.RegisterPlurality(new CommandBus()); + _container.RegisterPlurality(new QueryBus()); + _container.RegisterPlurality(new DefaultEnvironment()); + _container.RegisterPlurality(new AsyncQueryBus()); + _context = new ArchitectureContext(_container); } private ArchitectureContext _context = null!; diff --git a/GFramework.Core/architecture/Architecture.cs b/GFramework.Core/architecture/Architecture.cs index eb20da2..77a8ec9 100644 --- a/GFramework.Core/architecture/Architecture.cs +++ b/GFramework.Core/architecture/Architecture.cs @@ -1,5 +1,4 @@ using GFramework.Core.Abstractions.architecture; -using GFramework.Core.Abstractions.command; using GFramework.Core.Abstractions.enums; using GFramework.Core.Abstractions.environment; using GFramework.Core.Abstractions.events; @@ -7,14 +6,12 @@ using GFramework.Core.Abstractions.ioc; using GFramework.Core.Abstractions.lifecycle; using GFramework.Core.Abstractions.logging; using GFramework.Core.Abstractions.model; -using GFramework.Core.Abstractions.query; using GFramework.Core.Abstractions.system; using GFramework.Core.Abstractions.utility; using GFramework.Core.environment; using GFramework.Core.events; using GFramework.Core.extensions; using GFramework.Core.logging; -using IAsyncQueryBus = GFramework.Core.Abstractions.query.IAsyncQueryBus; using IDisposable = GFramework.Core.Abstractions.lifecycle.IDisposable; namespace GFramework.Core.architecture; @@ -79,21 +76,6 @@ public abstract class Architecture( /// private IEventBus EventBus => Services.EventBus; - /// - /// 获取命令总线 - /// - private ICommandBus CommandBus => Services.CommandBus; - - /// - /// 获取查询总线 - /// - private IQueryBus QueryBus => Services.QueryBus; - - /// - /// 获取异步查询总线 - /// - private IAsyncQueryBus AsyncQueryBus => Services.AsyncQueryBus; - /// /// 当前架构的阶段 /// @@ -553,8 +535,12 @@ public abstract class Architecture( _logger = LoggerFactoryResolver.Provider.CreateLogger(GetType().Name); Environment.Initialize(); + // 将 Environment 注册到容器(如果尚未注册) + if (!Container.Contains()) + Container.RegisterPlurality(Environment); + // 初始化架构上下文(如果尚未初始化) - _context ??= new ArchitectureContext(Container, EventBus, CommandBus, QueryBus, Environment, AsyncQueryBus); + _context ??= new ArchitectureContext(Container); GameContext.Bind(GetType(), _context); // 为服务设置上下文 diff --git a/GFramework.Core/architecture/ArchitectureContext.cs b/GFramework.Core/architecture/ArchitectureContext.cs index 567f9dd..744d371 100644 --- a/GFramework.Core/architecture/ArchitectureContext.cs +++ b/GFramework.Core/architecture/ArchitectureContext.cs @@ -7,34 +7,38 @@ using GFramework.Core.Abstractions.model; using GFramework.Core.Abstractions.query; using GFramework.Core.Abstractions.system; using GFramework.Core.Abstractions.utility; -using IAsyncQueryBus = GFramework.Core.Abstractions.query.IAsyncQueryBus; namespace GFramework.Core.architecture; /// /// 架构上下文类,提供对系统、模型、工具等组件的访问以及命令、查询、事件的执行管理 /// -public class ArchitectureContext( - IIocContainer container, - IEventBus eventBus, - ICommandBus commandBus, - IQueryBus queryBus, - IEnvironment environment, - IAsyncQueryBus asyncQueryBus) - : IArchitectureContext +public class ArchitectureContext : IArchitectureContext { - private readonly IAsyncQueryBus _asyncQueryBus = - asyncQueryBus ?? throw new ArgumentNullException(nameof(asyncQueryBus)); + private readonly IIocContainer _container; + private readonly Dictionary _serviceCache = new(); - private readonly ICommandBus _commandBus = commandBus ?? throw new ArgumentNullException(nameof(commandBus)); - private readonly IIocContainer _container = container ?? throw new ArgumentNullException(nameof(container)); + public ArchitectureContext(IIocContainer container) + { + _container = container ?? throw new ArgumentNullException(nameof(container)); + } - private readonly IEnvironment _environment = environment ?? throw new ArgumentNullException(nameof(environment)); + public TService? GetService() where TService : class + { + return GetOrCache(); + } - private readonly IEventBus _eventBus = - eventBus ?? throw new ArgumentNullException(nameof(eventBus)); + private TService? GetOrCache() where TService : class + { + if (_serviceCache.TryGetValue(typeof(TService), out var cached)) + return (TService)cached; - private readonly IQueryBus _queryBus = queryBus ?? throw new ArgumentNullException(nameof(queryBus)); + var service = _container.Get(); + if (service != null) + _serviceCache[typeof(TService)] = service; + + return service; + } #region Query Execution @@ -46,7 +50,10 @@ public class ArchitectureContext( /// 查询结果 public TResult SendQuery(IQuery query) { - return query == null ? throw new ArgumentNullException(nameof(query)) : _queryBus.Send(query); + if (query == null) throw new ArgumentNullException(nameof(query)); + var queryBus = GetOrCache(); + if (queryBus == null) throw new InvalidOperationException("IQueryBus not registered"); + return queryBus.Send(query); } /// @@ -55,9 +62,12 @@ public class ArchitectureContext( /// 查询结果类型 /// 要发送的异步查询 /// 查询结果 - public Task SendQueryAsync(IAsyncQuery query) + public async Task SendQueryAsync(IAsyncQuery query) { - return query == null ? throw new ArgumentNullException(nameof(query)) : _asyncQueryBus.SendAsync(query); + if (query == null) throw new ArgumentNullException(nameof(query)); + var asyncQueryBus = GetOrCache(); + if (asyncQueryBus == null) throw new InvalidOperationException("IAsyncQueryBus not registered"); + return await asyncQueryBus.SendAsync(query); } #endregion @@ -71,7 +81,7 @@ public class ArchitectureContext( /// 对应的系统实例 public TSystem? GetSystem() where TSystem : class, ISystem { - return _container.Get(); + return GetService(); } /// @@ -81,7 +91,7 @@ public class ArchitectureContext( /// 对应的模型实例 public TModel? GetModel() where TModel : class, IModel { - return _container.Get(); + return GetService(); } /// @@ -91,7 +101,7 @@ public class ArchitectureContext( /// 对应的工具实例 public TUtility? GetUtility() where TUtility : class, IUtility { - return _container.Get(); + return GetService(); } #endregion @@ -105,7 +115,8 @@ public class ArchitectureContext( public void SendCommand(ICommand command) { ArgumentNullException.ThrowIfNull(command); - _commandBus.Send(command); + var commandBus = GetOrCache(); + commandBus?.Send(command); } /// @@ -117,7 +128,9 @@ public class ArchitectureContext( public TResult SendCommand(ICommand command) { ArgumentNullException.ThrowIfNull(command); - return _commandBus.Send(command); + var commandBus = GetOrCache(); + if (commandBus == null) throw new InvalidOperationException("ICommandBus not registered"); + return commandBus.Send(command); } /// @@ -127,7 +140,9 @@ public class ArchitectureContext( public async Task SendCommandAsync(IAsyncCommand command) { ArgumentNullException.ThrowIfNull(command); - await _commandBus.SendAsync(command); + var commandBus = GetOrCache(); + if (commandBus == null) throw new InvalidOperationException("ICommandBus not registered"); + await commandBus.SendAsync(command); } /// @@ -139,7 +154,9 @@ public class ArchitectureContext( public async Task SendCommandAsync(IAsyncCommand command) { ArgumentNullException.ThrowIfNull(command); - return await _commandBus.SendAsync(command); + var commandBus = GetOrCache(); + if (commandBus == null) throw new InvalidOperationException("ICommandBus not registered"); + return await commandBus.SendAsync(command); } #endregion @@ -152,7 +169,8 @@ public class ArchitectureContext( /// 事件类型 public void SendEvent() where TEvent : new() { - _eventBus.Send(); + var eventBus = GetOrCache(); + eventBus?.Send(); } /// @@ -163,7 +181,8 @@ public class ArchitectureContext( public void SendEvent(TEvent e) where TEvent : class { ArgumentNullException.ThrowIfNull(e); - _eventBus.Send(e); + var eventBus = GetOrCache(); + eventBus?.Send(e); } /// @@ -174,7 +193,10 @@ public class ArchitectureContext( /// 事件注销接口 public IUnRegister RegisterEvent(Action handler) { - return handler == null ? throw new ArgumentNullException(nameof(handler)) : _eventBus.Register(handler); + ArgumentNullException.ThrowIfNull(handler); + var eventBus = GetOrCache(); + if (eventBus == null) throw new InvalidOperationException("IEventBus not registered"); + return eventBus.Register(handler); } /// @@ -185,7 +207,8 @@ public class ArchitectureContext( public void UnRegisterEvent(Action onEvent) { ArgumentNullException.ThrowIfNull(onEvent); - _eventBus.UnRegister(onEvent); + var eventBus = GetOrCache(); + eventBus?.UnRegister(onEvent); } /// @@ -194,7 +217,8 @@ public class ArchitectureContext( /// 环境对象实例 public IEnvironment GetEnvironment() { - return _environment; + var environment = GetOrCache(); + return environment ?? throw new InvalidOperationException("IEnvironment not registered"); } #endregion diff --git a/GFramework.Core/architecture/ArchitectureServices.cs b/GFramework.Core/architecture/ArchitectureServices.cs index 0f7c7cc..c97a9ea 100644 --- a/GFramework.Core/architecture/ArchitectureServices.cs +++ b/GFramework.Core/architecture/ArchitectureServices.cs @@ -16,32 +16,74 @@ namespace GFramework.Core.architecture; /// public class ArchitectureServices : IArchitectureServices { + /// + /// 异步查询总线实例 + /// + private readonly IAsyncQueryBus _asyncQueryBus; + + /// + /// 命令总线实例 + /// + private readonly ICommandBus _commandBus; + + private readonly IIocContainer _container; + + /// + /// 事件总线实例 + /// + private readonly IEventBus _eventBus; + + /// + /// 查询总线实例 + /// + private readonly IQueryBus _queryBus; + private IArchitectureContext _context = null!; + /// + /// 构造函数,初始化架构服务 + /// + public ArchitectureServices() + { + _container = new IocContainer(); + + // 创建服务实例 + _eventBus = new EventBus(); + _commandBus = new CommandBus(); + _queryBus = new QueryBus(); + _asyncQueryBus = new AsyncQueryBus(); + + // 将服务注册到容器 + _container.RegisterPlurality(_eventBus); + _container.RegisterPlurality(_commandBus); + _container.RegisterPlurality(_queryBus); + _container.RegisterPlurality(_asyncQueryBus); + } + /// /// 获取依赖注入容器 /// - public IIocContainer Container { get; } = new IocContainer(); + public IIocContainer Container => _container; /// /// 获取类型事件系统 /// - public IEventBus EventBus { get; } = new EventBus(); + public IEventBus EventBus => _eventBus; /// /// 获取命令总线 /// - public ICommandBus CommandBus { get; } = new CommandBus(); + public ICommandBus CommandBus => _commandBus; /// /// 获取查询总线 /// - public IQueryBus QueryBus { get; } = new QueryBus(); + public IQueryBus QueryBus => _queryBus; /// /// 获取异步查询总线 /// - public IAsyncQueryBus AsyncQueryBus { get; } = new AsyncQueryBus(); + public IAsyncQueryBus AsyncQueryBus => _asyncQueryBus; /// /// 设置架构上下文