feat(architecture): 添加环境配置支持并重构架构初始化

- 引入IEnvironment接口和EnvironmentBase抽象类实现环境管理
- 在Architecture类中添加environment参数和Environment属性
- 修改ArchitectureContext构造函数以接收环境对象
- 添加DefaultEnvironment默认环境实现类
- 更新ContextAwareExtensions扩展方法支持环境获取
- 移除NoopLogger和NoopLoggerFactory无操作日志类
- 重构架构初始化流程以包含环境初始化
- 添加GetEnvironment扩展方法用于获取环境对象
This commit is contained in:
GwWuYou 2026-01-03 21:44:22 +08:00
parent 4adf3f11d4
commit 49ceb35156
11 changed files with 244 additions and 67 deletions

View File

@ -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
/// <typeparam name="TEvent">事件类型</typeparam>
/// <param name="onEvent">要取消注册的事件回调方法</param>
void UnRegisterEvent<TEvent>(Action<TEvent> onEvent);
/// <summary>
/// 获取环境对象
/// </summary>
/// <returns>环境对象实例</returns>
IEnvironment GetEnvironment();
}

View File

@ -0,0 +1,50 @@
namespace GFramework.Core.Abstractions.environment;
/// <summary>
/// 定义环境接口,提供应用程序运行环境的相关信息
/// </summary>
public interface IEnvironment
{
/// <summary>
/// 获取环境名称
/// </summary>
public string Name { get; }
/// <summary>
/// 根据键值获取指定类型的环境配置值
/// </summary>
/// <typeparam name="T">要获取的值的类型,必须为引用类型</typeparam>
/// <param name="key">用于查找配置值的键</param>
/// <returns>与指定键关联的配置值如果未找到则返回null</returns>
T? Get<T>(string key) where T : class;
/// <summary>
/// 尝试获取环境值(显式判断)
/// </summary>
/// <typeparam name="T">要获取的值的类型,必须为引用类型</typeparam>
/// <param name="key">用于查找配置值的键</param>
/// <param name="value">输出参数,如果找到配置值则返回该值,否则返回默认值</param>
/// <returns>如果找到指定键的配置值则返回true否则返回false</returns>
bool TryGet<T>(string key, out T value) where T : class;
/// <summary>
/// 获取必须存在的环境值(强依赖)
/// </summary>
/// <typeparam name="T">要获取的值的类型,必须为引用类型</typeparam>
/// <param name="key">用于查找配置值的键</param>
/// <returns>与指定键关联的配置值,如果未找到则抛出异常</returns>
T GetRequired<T>(string key) where T : class;
/// <summary>
/// 注册键值对到环境值字典中
/// </summary>
/// <param name="key">要注册的键</param>
/// <param name="value">要注册的值</param>
void Register(string key, object value);
/// <summary>
/// 初始化环境值字典
/// </summary>
void Initialize();
}

View File

@ -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;
/// </summary>
public abstract class Architecture(
IArchitectureConfiguration? configuration = null,
IEnvironment? environment = null,
IArchitectureServices? services = null,
IArchitectureContext? context = null
)
: IArchitecture
{
/// <summary>
/// 获取架构配置对象
/// 获取架构配置对象
/// </summary>
/// <value>
/// 返回一个IArchitectureConfiguration接口的实例默认为DefaultArchitectureConfiguration类型
/// 返回一个IArchitectureConfiguration接口的实例默认为DefaultArchitectureConfiguration类型
/// </value>
private IArchitectureConfiguration Configuration { get; } = configuration ?? new ArchitectureConfiguration();
/// <summary>
/// 获取环境配置对象
/// </summary>
/// <value>
/// 返回一个IEnvironment接口的实例默认为DefaultEnvironment类型
/// </value>
private IEnvironment Environment { get; } = environment ?? new DefaultEnvironment();
/// <summary>
/// 获取架构服务对象
/// </summary>
@ -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);

View File

@ -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);
}
/// <summary>
/// 获取当前环境对象
/// </summary>
/// <returns>环境对象实例</returns>
public IEnvironment GetEnvironment()
{
return _environment;
}
#endregion
}

View File

@ -0,0 +1,19 @@
namespace GFramework.Core.environment;
/// <summary>
/// 默认环境实现类继承自EnvironmentBase
/// </summary>
public class DefaultEnvironment : EnvironmentBase
{
/// <summary>
/// 获取环境名称
/// </summary>
public override string Name { get; } = "Default";
/// <summary>
/// 初始化环境
/// </summary>
public override void Initialize()
{
}
}

View File

@ -0,0 +1,83 @@
using GFramework.Core.Abstractions.environment;
using GFramework.Core.rule;
namespace GFramework.Core.environment;
/// <summary>
/// 环境基础抽象类实现了IEnvironment接口提供环境值的存储和获取功能
/// </summary>
public abstract class EnvironmentBase : ContextAwareBase, IEnvironment
{
/// <summary>
/// 存储环境值的字典,键为字符串,值为对象类型
/// </summary>
protected readonly Dictionary<string, object> Values = new();
/// <summary>
/// 获取环境名称的抽象属性
/// </summary>
public abstract string Name { get; }
/// <summary>
/// 根据键获取指定类型的值
/// </summary>
/// <typeparam name="T">要获取的值的类型,必须为引用类型</typeparam>
/// <param name="key">用于查找值的键</param>
/// <returns>如果找到则返回对应类型的值否则返回null</returns>
public virtual T? Get<T>(string key) where T : class
{
return TryGet<T>(key, out var value) ? value : null;
}
/// <summary>
/// 尝试根据键获取指定类型的值
/// </summary>
/// <typeparam name="T">要获取的值的类型,必须为引用类型</typeparam>
/// <param name="key">用于查找值的键</param>
/// <param name="value">输出参数如果成功则包含找到的值否则为null</param>
/// <returns>如果找到指定键且类型匹配则返回true否则返回false</returns>
public virtual bool TryGet<T>(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;
}
/// <summary>
/// 根据键获取必需的指定类型值,如果找不到则抛出异常
/// </summary>
/// <typeparam name="T">要获取的值的类型,必须为引用类型</typeparam>
/// <param name="key">用于查找值的键</param>
/// <returns>找到的对应类型的值</returns>
/// <exception cref="InvalidOperationException">当指定键的值不存在时抛出</exception>
public virtual T GetRequired<T>(string key) where T : class
{
if (TryGet<T>(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();
/// <summary>
/// 注册键值对到环境值字典中
/// </summary>
/// <param name="key">要注册的键</param>
/// <param name="value">要注册的值</param>
protected void Register(string key, object value)
{
Values[key] = value;
}
}

View File

@ -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
/// <exception cref="ArgumentNullException">当 contextAware 为 null 时抛出</exception>
public static TSystem? GetSystem<TSystem>(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<TSystem>();
}
@ -36,7 +37,7 @@ public static class ContextAwareExtensions
/// <exception cref="ArgumentNullException">当 contextAware 为 null 时抛出</exception>
public static TModel? GetModel<TModel>(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<TModel>();
}
@ -50,7 +51,7 @@ public static class ContextAwareExtensions
/// <exception cref="ArgumentNullException">当 contextAware 为 null 时抛出</exception>
public static TUtility? GetUtility<TUtility>(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<TUtility>();
}
@ -65,8 +66,8 @@ public static class ContextAwareExtensions
/// <exception cref="ArgumentNullException">当 contextAware 或 query 为 null 时抛出</exception>
public static TResult SendQuery<TResult>(this IContextAware contextAware, IQuery<TResult> 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
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
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
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
public static TResult SendCommand<TResult>(this IContextAware contextAware, ICommand<TResult> 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
/// <exception cref="ArgumentNullException">当 contextAware 为 null 时抛出</exception>
public static void SendEvent<TEvent>(this IContextAware contextAware) where TEvent : new()
{
if (contextAware == null) throw new ArgumentNullException(nameof(contextAware));
ArgumentNullException.ThrowIfNull(contextAware);
var context = contextAware.GetContext();
context.SendEvent<TEvent>();
}
@ -126,8 +127,8 @@ public static class ContextAwareExtensions
/// <exception cref="ArgumentNullException">当 contextAware 或 e 为 null 时抛出</exception>
public static void SendEvent<TEvent>(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
/// <returns>事件注销接口</returns>
public static IUnRegister RegisterEvent<TEvent>(this IContextAware contextAware, Action<TEvent> 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
/// <param name="onEvent">之前绑定的事件处理器</param>
public static void UnRegisterEvent<TEvent>(this IContextAware contextAware, Action<TEvent> 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);
}
/// <summary>
/// 获取指定类型的环境对象
/// </summary>
/// <typeparam name="T">要获取的环境对象类型</typeparam>
/// <param name="contextAware">上下文感知对象</param>
/// <returns>指定类型的环境对象如果无法转换则返回null</returns>
public static T? GetEnvironment<T>(this IContextAware contextAware) where T : class
{
ArgumentNullException.ThrowIfNull(contextAware);
// 获取上下文对象并返回其环境
var context = contextAware.GetContext();
return context.GetEnvironment() as T;
}
/// <summary>
/// 获取环境对象
/// </summary>
/// <param name="contextAware">上下文感知对象</param>
/// <returns>环境对象</returns>
public static IEnvironment GetEnvironment(this IContextAware contextAware)
{
ArgumentNullException.ThrowIfNull(contextAware);
// 获取上下文对象并返回其环境
var context = contextAware.GetContext();
return context.GetEnvironment();
}
}

View File

@ -1,23 +0,0 @@
using GFramework.Core.Abstractions.logging;
namespace GFramework.Core.logging;
/// <summary>
/// 空操作日志记录器实现,不执行任何实际的日志记录操作
/// </summary>
/// <param name="name">日志记录器名称默认为null</param>
/// <param name="minLevel">最小日志级别默认为Info</param>
internal sealed class NoopLogger(
string? name = null,
LogLevel minLevel = LogLevel.Info) : AbstractLogger(name ?? RootLoggerName, minLevel)
{
/// <summary>
/// 重写写入方法,空操作实现,不执行任何实际的日志记录操作
/// </summary>
/// <param name="level">日志级别</param>
/// <param name="message">日志消息</param>
/// <param name="exception">异常信息</param>
protected override void Write(LogLevel level, string message, Exception? exception)
{
}
}

View File

@ -1,20 +0,0 @@
using GFramework.Core.Abstractions.logging;
namespace GFramework.Core.logging;
/// <summary>
/// 无操作日志工厂实现,用于提供空的日志记录功能
/// </summary>
public class NoopLoggerFactory : ILoggerFactory
{
/// <summary>
/// 获取指定名称的无操作日志记录器
/// </summary>
/// <param name="name">日志记录器的名称</param>
/// <param name="minLevel">日志记录器的最小日志级别</param>
/// <returns>返回一个NoopLogger实例该实例不执行任何实际的日志记录操作</returns>
public ILogger GetLogger(string name, LogLevel minLevel = LogLevel.Info)
{
return new NoopLogger();
}
}

View File

@ -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;
/// </summary>
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)
{
/// <summary>
/// 存储所有已安装的Godot架构扩展组件列表

View File

@ -1,4 +1,5 @@
using Godot;
using System;
using Godot;
namespace GFramework.Godot.architecture;