From 49ceb35156c9fe26aacd2e0b578d167d4e9281b6 Mon Sep 17 00:00:00 2001 From: GwWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Sat, 3 Jan 2026 21:44:22 +0800 Subject: [PATCH] =?UTF-8?q?feat(architecture):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E9=85=8D=E7=BD=AE=E6=94=AF=E6=8C=81=E5=B9=B6?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E6=9E=B6=E6=9E=84=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 引入IEnvironment接口和EnvironmentBase抽象类实现环境管理 - 在Architecture类中添加environment参数和Environment属性 - 修改ArchitectureContext构造函数以接收环境对象 - 添加DefaultEnvironment默认环境实现类 - 更新ContextAwareExtensions扩展方法支持环境获取 - 移除NoopLogger和NoopLoggerFactory无操作日志类 - 重构架构初始化流程以包含环境初始化 - 添加GetEnvironment扩展方法用于获取环境对象 --- .../architecture/IArchitectureContext.cs | 7 ++ .../environment/IEnvironment.cs | 50 +++++++++++ GFramework.Core/architecture/Architecture.cs | 20 ++++- .../architecture/ArchitectureContext.cs | 15 +++- .../environment/DefaultEnvironment.cs | 19 +++++ .../environment/EnvironmentBase.cs | 83 +++++++++++++++++++ .../extensions/ContextAwareExtensions.cs | 62 ++++++++++---- GFramework.Core/logging/NoopLogger.cs | 23 ----- GFramework.Core/logging/NoopLoggerFactory.cs | 20 ----- .../architecture/AbstractArchitecture.cs | 9 +- .../architecture/ArchitectureAnchor.cs | 3 +- 11 files changed, 244 insertions(+), 67 deletions(-) create mode 100644 GFramework.Core.Abstractions/environment/IEnvironment.cs create mode 100644 GFramework.Core/environment/DefaultEnvironment.cs create mode 100644 GFramework.Core/environment/EnvironmentBase.cs delete mode 100644 GFramework.Core/logging/NoopLogger.cs delete mode 100644 GFramework.Core/logging/NoopLoggerFactory.cs diff --git a/GFramework.Core.Abstractions/architecture/IArchitectureContext.cs b/GFramework.Core.Abstractions/architecture/IArchitectureContext.cs index aa2451c..d02c877 100644 --- a/GFramework.Core.Abstractions/architecture/IArchitectureContext.cs +++ b/GFramework.Core.Abstractions/architecture/IArchitectureContext.cs @@ -1,5 +1,6 @@ using System; using GFramework.Core.Abstractions.command; +using GFramework.Core.Abstractions.environment; using GFramework.Core.Abstractions.events; using GFramework.Core.Abstractions.model; using GFramework.Core.Abstractions.query; @@ -83,4 +84,10 @@ public interface IArchitectureContext /// 事件类型 /// 要取消注册的事件回调方法 void UnRegisterEvent(Action onEvent); + + /// + /// 获取环境对象 + /// + /// 环境对象实例 + IEnvironment GetEnvironment(); } \ No newline at end of file diff --git a/GFramework.Core.Abstractions/environment/IEnvironment.cs b/GFramework.Core.Abstractions/environment/IEnvironment.cs new file mode 100644 index 0000000..9c75bfb --- /dev/null +++ b/GFramework.Core.Abstractions/environment/IEnvironment.cs @@ -0,0 +1,50 @@ +namespace GFramework.Core.Abstractions.environment; + +/// +/// 定义环境接口,提供应用程序运行环境的相关信息 +/// +public interface IEnvironment +{ + /// + /// 获取环境名称 + /// + public string Name { get; } + + + /// + /// 根据键值获取指定类型的环境配置值 + /// + /// 要获取的值的类型,必须为引用类型 + /// 用于查找配置值的键 + /// 与指定键关联的配置值,如果未找到则返回null + T? Get(string key) where T : class; + + /// + /// 尝试获取环境值(显式判断) + /// + /// 要获取的值的类型,必须为引用类型 + /// 用于查找配置值的键 + /// 输出参数,如果找到配置值则返回该值,否则返回默认值 + /// 如果找到指定键的配置值则返回true,否则返回false + bool TryGet(string key, out T value) where T : class; + + /// + /// 获取必须存在的环境值(强依赖) + /// + /// 要获取的值的类型,必须为引用类型 + /// 用于查找配置值的键 + /// 与指定键关联的配置值,如果未找到则抛出异常 + T GetRequired(string key) where T : class; + + /// + /// 注册键值对到环境值字典中 + /// + /// 要注册的键 + /// 要注册的值 + void Register(string key, object value); + + /// + /// 初始化环境值字典 + /// + void Initialize(); +} \ No newline at end of file diff --git a/GFramework.Core/architecture/Architecture.cs b/GFramework.Core/architecture/Architecture.cs index 4c58c44..dda7ad9 100644 --- a/GFramework.Core/architecture/Architecture.cs +++ b/GFramework.Core/architecture/Architecture.cs @@ -1,6 +1,7 @@ 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; using GFramework.Core.Abstractions.ioc; using GFramework.Core.Abstractions.logging; @@ -8,6 +9,7 @@ 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.logging; @@ -20,19 +22,29 @@ namespace GFramework.Core.architecture; /// public abstract class Architecture( IArchitectureConfiguration? configuration = null, + IEnvironment? environment = null, IArchitectureServices? services = null, IArchitectureContext? context = null ) : IArchitecture { /// - /// 获取架构配置对象 + /// 获取架构配置对象 /// /// - /// 返回一个IArchitectureConfiguration接口的实例,默认为DefaultArchitectureConfiguration类型 + /// 返回一个IArchitectureConfiguration接口的实例,默认为DefaultArchitectureConfiguration类型 /// private IArchitectureConfiguration Configuration { get; } = configuration ?? new ArchitectureConfiguration(); + /// + /// 获取环境配置对象 + /// + /// + /// 返回一个IEnvironment接口的实例,默认为DefaultEnvironment类型 + /// + private IEnvironment Environment { get; } = environment ?? new DefaultEnvironment(); + + /// /// 获取架构服务对象 /// @@ -304,9 +316,9 @@ public abstract class Architecture( LoggerFactoryResolver.Provider = Configuration.LoggerProperties.LoggerFactoryProvider; // 创建日志记录器实例 _logger = LoggerFactoryResolver.Provider.CreateLogger(GetType().Name); - + Environment.Initialize(); // 初始化架构上下文(如果尚未初始化) - _context ??= new ArchitectureContext(Container, TypeEventSystem, CommandBus, QueryBus); + _context ??= new ArchitectureContext(Container, TypeEventSystem, CommandBus, QueryBus, Environment); // 将当前架构类型与上下文绑定到游戏上下文 GameContext.Bind(GetType(), _context); diff --git a/GFramework.Core/architecture/ArchitectureContext.cs b/GFramework.Core/architecture/ArchitectureContext.cs index 606a0a3..7e01224 100644 --- a/GFramework.Core/architecture/ArchitectureContext.cs +++ b/GFramework.Core/architecture/ArchitectureContext.cs @@ -1,5 +1,6 @@ using GFramework.Core.Abstractions.architecture; using GFramework.Core.Abstractions.command; +using GFramework.Core.Abstractions.environment; using GFramework.Core.Abstractions.events; using GFramework.Core.Abstractions.ioc; using GFramework.Core.Abstractions.model; @@ -16,11 +17,14 @@ public class ArchitectureContext( IIocContainer container, ITypeEventSystem typeEventSystem, ICommandBus commandBus, - IQueryBus queryBus) + IQueryBus queryBus, + IEnvironment environment) : IArchitectureContext { private readonly ICommandBus _commandBus = commandBus ?? throw new ArgumentNullException(nameof(commandBus)); private readonly IIocContainer _container = container ?? throw new ArgumentNullException(nameof(container)); + + private readonly IEnvironment _environment = environment ?? throw new ArgumentNullException(nameof(environment)); private readonly IQueryBus _queryBus = queryBus ?? throw new ArgumentNullException(nameof(queryBus)); private readonly ITypeEventSystem _typeEventSystem = @@ -145,5 +149,14 @@ public class ArchitectureContext( _typeEventSystem.UnRegister(onEvent); } + /// + /// 获取当前环境对象 + /// + /// 环境对象实例 + public IEnvironment GetEnvironment() + { + return _environment; + } + #endregion } \ No newline at end of file diff --git a/GFramework.Core/environment/DefaultEnvironment.cs b/GFramework.Core/environment/DefaultEnvironment.cs new file mode 100644 index 0000000..39644c7 --- /dev/null +++ b/GFramework.Core/environment/DefaultEnvironment.cs @@ -0,0 +1,19 @@ +namespace GFramework.Core.environment; + +/// +/// 默认环境实现类,继承自EnvironmentBase +/// +public class DefaultEnvironment : EnvironmentBase +{ + /// + /// 获取环境名称 + /// + public override string Name { get; } = "Default"; + + /// + /// 初始化环境 + /// + public override void Initialize() + { + } +} \ No newline at end of file diff --git a/GFramework.Core/environment/EnvironmentBase.cs b/GFramework.Core/environment/EnvironmentBase.cs new file mode 100644 index 0000000..292033d --- /dev/null +++ b/GFramework.Core/environment/EnvironmentBase.cs @@ -0,0 +1,83 @@ +using GFramework.Core.Abstractions.environment; +using GFramework.Core.rule; + +namespace GFramework.Core.environment; + +/// +/// 环境基础抽象类,实现了IEnvironment接口,提供环境值的存储和获取功能 +/// +public abstract class EnvironmentBase : ContextAwareBase, IEnvironment +{ + /// + /// 存储环境值的字典,键为字符串,值为对象类型 + /// + protected readonly Dictionary Values = new(); + + /// + /// 获取环境名称的抽象属性 + /// + public abstract string Name { get; } + + /// + /// 根据键获取指定类型的值 + /// + /// 要获取的值的类型,必须为引用类型 + /// 用于查找值的键 + /// 如果找到则返回对应类型的值,否则返回null + public virtual T? Get(string key) where T : class + { + return TryGet(key, out var value) ? value : null; + } + + /// + /// 尝试根据键获取指定类型的值 + /// + /// 要获取的值的类型,必须为引用类型 + /// 用于查找值的键 + /// 输出参数,如果成功则包含找到的值,否则为null + /// 如果找到指定键且类型匹配则返回true,否则返回false + public virtual bool TryGet(string key, out T value) where T : class + { + if (Values.TryGetValue(key, out var obj) && obj is T typed) + { + value = typed; + return true; + } + + value = null!; + return false; + } + + /// + /// 根据键获取必需的指定类型值,如果找不到则抛出异常 + /// + /// 要获取的值的类型,必须为引用类型 + /// 用于查找值的键 + /// 找到的对应类型的值 + /// 当指定键的值不存在时抛出 + public virtual T GetRequired(string key) where T : class + { + if (TryGet(key, out var value)) + return value; + + throw new InvalidOperationException( + $"Environment [{Name}] missing required value: key='{key}', type='{typeof(T).Name}'"); + } + + void IEnvironment.Register(string key, object value) + { + Register(key, value); + } + + public abstract void Initialize(); + + /// + /// 注册键值对到环境值字典中 + /// + /// 要注册的键 + /// 要注册的值 + protected void Register(string key, object value) + { + Values[key] = value; + } +} \ No newline at end of file diff --git a/GFramework.Core/extensions/ContextAwareExtensions.cs b/GFramework.Core/extensions/ContextAwareExtensions.cs index 3a5af4b..0b79530 100644 --- a/GFramework.Core/extensions/ContextAwareExtensions.cs +++ b/GFramework.Core/extensions/ContextAwareExtensions.cs @@ -1,4 +1,5 @@ using GFramework.Core.Abstractions.command; +using GFramework.Core.Abstractions.environment; using GFramework.Core.Abstractions.events; using GFramework.Core.Abstractions.model; using GFramework.Core.Abstractions.query; @@ -22,7 +23,7 @@ public static class ContextAwareExtensions /// 当 contextAware 为 null 时抛出 public static TSystem? GetSystem(this IContextAware contextAware) where TSystem : class, ISystem { - if (contextAware == null) throw new ArgumentNullException(nameof(contextAware)); + ArgumentNullException.ThrowIfNull(contextAware); var context = contextAware.GetContext(); return context.GetSystem(); } @@ -36,7 +37,7 @@ public static class ContextAwareExtensions /// 当 contextAware 为 null 时抛出 public static TModel? GetModel(this IContextAware contextAware) where TModel : class, IModel { - if (contextAware == null) throw new ArgumentNullException(nameof(contextAware)); + ArgumentNullException.ThrowIfNull(contextAware); var context = contextAware.GetContext(); return context.GetModel(); } @@ -50,7 +51,7 @@ public static class ContextAwareExtensions /// 当 contextAware 为 null 时抛出 public static TUtility? GetUtility(this IContextAware contextAware) where TUtility : class, IUtility { - if (contextAware == null) throw new ArgumentNullException(nameof(contextAware)); + ArgumentNullException.ThrowIfNull(contextAware); var context = contextAware.GetContext(); return context.GetUtility(); } @@ -65,8 +66,8 @@ public static class ContextAwareExtensions /// 当 contextAware 或 query 为 null 时抛出 public static TResult SendQuery(this IContextAware contextAware, IQuery query) { - if (contextAware == null) throw new ArgumentNullException(nameof(contextAware)); - if (query == null) throw new ArgumentNullException(nameof(query)); + ArgumentNullException.ThrowIfNull(contextAware); + ArgumentNullException.ThrowIfNull(query); var context = contextAware.GetContext(); return context.SendQuery(query); @@ -80,8 +81,8 @@ public static class ContextAwareExtensions /// 当 contextAware 或 command 为 null 时抛出 public static void SendCommand(this IContextAware contextAware, ICommand command) { - if (contextAware == null) throw new ArgumentNullException(nameof(contextAware)); - if (command == null) throw new ArgumentNullException(nameof(command)); + ArgumentNullException.ThrowIfNull(contextAware); + ArgumentNullException.ThrowIfNull(command); var context = contextAware.GetContext(); context.SendCommand(command); @@ -97,8 +98,8 @@ public static class ContextAwareExtensions /// 当 contextAware 或 command 为 null 时抛出 public static TResult SendCommand(this IContextAware contextAware, ICommand command) { - if (contextAware == null) throw new ArgumentNullException(nameof(contextAware)); - if (command == null) throw new ArgumentNullException(nameof(command)); + ArgumentNullException.ThrowIfNull(contextAware); + ArgumentNullException.ThrowIfNull(command); var context = contextAware.GetContext(); return context.SendCommand(command); @@ -112,7 +113,7 @@ public static class ContextAwareExtensions /// 当 contextAware 为 null 时抛出 public static void SendEvent(this IContextAware contextAware) where TEvent : new() { - if (contextAware == null) throw new ArgumentNullException(nameof(contextAware)); + ArgumentNullException.ThrowIfNull(contextAware); var context = contextAware.GetContext(); context.SendEvent(); } @@ -126,8 +127,8 @@ public static class ContextAwareExtensions /// 当 contextAware 或 e 为 null 时抛出 public static void SendEvent(this IContextAware contextAware, TEvent e) where TEvent : class { - if (contextAware == null) throw new ArgumentNullException(nameof(contextAware)); - if (e == null) throw new ArgumentNullException(nameof(e)); + ArgumentNullException.ThrowIfNull(contextAware); + ArgumentNullException.ThrowIfNull(e); var context = contextAware.GetContext(); context.SendEvent(e); @@ -142,8 +143,8 @@ public static class ContextAwareExtensions /// 事件注销接口 public static IUnRegister RegisterEvent(this IContextAware contextAware, Action handler) { - if (contextAware == null) throw new ArgumentNullException(nameof(contextAware)); - if (handler == null) throw new ArgumentNullException(nameof(handler)); + ArgumentNullException.ThrowIfNull(contextAware); + ArgumentNullException.ThrowIfNull(handler); var context = contextAware.GetContext(); return context.RegisterEvent(handler); @@ -157,10 +158,39 @@ public static class ContextAwareExtensions /// 之前绑定的事件处理器 public static void UnRegisterEvent(this IContextAware contextAware, Action onEvent) { - if (contextAware == null) throw new ArgumentNullException(nameof(contextAware)); - if (onEvent == null) throw new ArgumentNullException(nameof(onEvent)); + ArgumentNullException.ThrowIfNull(contextAware); + ArgumentNullException.ThrowIfNull(onEvent); + // 获取上下文对象并取消事件注册 var context = contextAware.GetContext(); context.UnRegisterEvent(onEvent); } + + + /// + /// 获取指定类型的环境对象 + /// + /// 要获取的环境对象类型 + /// 上下文感知对象 + /// 指定类型的环境对象,如果无法转换则返回null + public static T? GetEnvironment(this IContextAware contextAware) where T : class + { + ArgumentNullException.ThrowIfNull(contextAware); + // 获取上下文对象并返回其环境 + var context = contextAware.GetContext(); + return context.GetEnvironment() as T; + } + + /// + /// 获取环境对象 + /// + /// 上下文感知对象 + /// 环境对象 + public static IEnvironment GetEnvironment(this IContextAware contextAware) + { + ArgumentNullException.ThrowIfNull(contextAware); + // 获取上下文对象并返回其环境 + var context = contextAware.GetContext(); + return context.GetEnvironment(); + } } \ No newline at end of file diff --git a/GFramework.Core/logging/NoopLogger.cs b/GFramework.Core/logging/NoopLogger.cs deleted file mode 100644 index b598d7a..0000000 --- a/GFramework.Core/logging/NoopLogger.cs +++ /dev/null @@ -1,23 +0,0 @@ -using GFramework.Core.Abstractions.logging; - -namespace GFramework.Core.logging; - -/// -/// 空操作日志记录器实现,不执行任何实际的日志记录操作 -/// -/// 日志记录器名称,默认为null -/// 最小日志级别,默认为Info -internal sealed class NoopLogger( - string? name = null, - LogLevel minLevel = LogLevel.Info) : AbstractLogger(name ?? RootLoggerName, minLevel) -{ - /// - /// 重写写入方法,空操作实现,不执行任何实际的日志记录操作 - /// - /// 日志级别 - /// 日志消息 - /// 异常信息 - protected override void Write(LogLevel level, string message, Exception? exception) - { - } -} \ No newline at end of file diff --git a/GFramework.Core/logging/NoopLoggerFactory.cs b/GFramework.Core/logging/NoopLoggerFactory.cs deleted file mode 100644 index 1d493e6..0000000 --- a/GFramework.Core/logging/NoopLoggerFactory.cs +++ /dev/null @@ -1,20 +0,0 @@ -using GFramework.Core.Abstractions.logging; - -namespace GFramework.Core.logging; - -/// -/// 无操作日志工厂实现,用于提供空的日志记录功能 -/// -public class NoopLoggerFactory : ILoggerFactory -{ - /// - /// 获取指定名称的无操作日志记录器 - /// - /// 日志记录器的名称 - /// 日志记录器的最小日志级别 - /// 返回一个NoopLogger实例,该实例不执行任何实际的日志记录操作 - public ILogger GetLogger(string name, LogLevel minLevel = LogLevel.Info) - { - return new NoopLogger(); - } -} \ No newline at end of file diff --git a/GFramework.Godot/architecture/AbstractArchitecture.cs b/GFramework.Godot/architecture/AbstractArchitecture.cs index 621575e..fb43ecb 100644 --- a/GFramework.Godot/architecture/AbstractArchitecture.cs +++ b/GFramework.Godot/architecture/AbstractArchitecture.cs @@ -1,4 +1,8 @@ -using GFramework.Core.Abstractions.architecture; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using GFramework.Core.Abstractions.architecture; +using GFramework.Core.Abstractions.environment; using GFramework.Core.architecture; using GFramework.Core.constants; using GFramework.Godot.extensions; @@ -12,9 +16,10 @@ namespace GFramework.Godot.architecture; /// public abstract class AbstractArchitecture( IArchitectureConfiguration? configuration = null, + IEnvironment? environment = null, IArchitectureServices? services = null, IArchitectureContext? context = null -) : Architecture(configuration, services, context) +) : Architecture(configuration, environment, services, context) { /// /// 存储所有已安装的Godot架构扩展组件列表 diff --git a/GFramework.Godot/architecture/ArchitectureAnchor.cs b/GFramework.Godot/architecture/ArchitectureAnchor.cs index 2884184..2dbe047 100644 --- a/GFramework.Godot/architecture/ArchitectureAnchor.cs +++ b/GFramework.Godot/architecture/ArchitectureAnchor.cs @@ -1,4 +1,5 @@ -using Godot; +using System; +using Godot; namespace GFramework.Godot.architecture;