feat(core): 重构资源工厂系统以支持键控资源注册与解析

- 引入基于键的资源工厂注册机制,替换原有的类型唯一注册方式
- 更新资源工厂接口,新增 GetFactory 方法支持键名参数
- 修改内部注册表结构,使用 (Type, string) 元组作为工厂字典键
- 在注册场景和资源时传入键名,确保资源可按名称区分
- 增强资源工厂条目信息,添加 ResourceType 和 Key 属性
- 完善工厂解析逻辑,通过类型和键双重条件匹配目标工厂
- 添加对空键值的校验,防止无效键导致运行时错误
- 优化预加载流程,仅执行明确标记为预加载的资源工厂
This commit is contained in:
GwWuYou 2025-12-18 21:19:14 +08:00
parent 8123683e6e
commit 24fa11cf1b
3 changed files with 76 additions and 25 deletions

View File

@ -35,18 +35,29 @@ public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceF
_registry.PreloadAll(); _registry.PreloadAll();
}); });
} }
/// <summary> /// <summary>
/// 注册系统所需的各种资源类型。由子类实现具体注册逻辑。 /// 注册系统所需的各种资源类型。由子类实现具体注册逻辑。
/// </summary> /// </summary>
protected abstract void RegisterResources(); protected abstract void RegisterResources();
/// <summary> /// <summary>
/// 获取指定类型的资源工厂函数。 /// 根据指定的键获取资源工厂函数。
/// </summary> /// </summary>
/// <typeparam name="T">要获取工厂的资源类型</typeparam> /// <typeparam name="T">资源类型</typeparam>
/// <param name="key">资源键</param>
/// <returns>返回创建指定类型资源的工厂函数</returns> /// <returns>返回创建指定类型资源的工厂函数</returns>
public Func<T> Get<T>() => _registry!.Resolve<T>(); public Func<T> GetFactory<T>(string key)=>_registry!.ResolveFactory<T>(key);
/// <summary>
/// 根据资产目录映射信息获取资源工厂函数。
/// </summary>
/// <typeparam name="T">资源类型</typeparam>
/// <param name="mapping">资产目录映射信息</param>
/// <returns>返回创建指定类型资源的工厂函数</returns>
public Func<T> GetFactory<T>(AssetCatalog.AssetCatalogMapping mapping) => _registry!.ResolveFactory<T>(mapping.Key);
#region Register Helpers #region Register Helpers
@ -65,6 +76,7 @@ public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceF
var id = _assetCatalogSystem!.GetScene(sceneKey); var id = _assetCatalogSystem!.GetScene(sceneKey);
_registry!.Register( _registry!.Register(
sceneKey,
_resourceLoadSystem!.GetOrRegisterSceneFactory<T>(id), _resourceLoadSystem!.GetOrRegisterSceneFactory<T>(id),
preload preload
); );
@ -87,6 +99,7 @@ public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceF
var id = _assetCatalogSystem!.GetResource(resourceKey); var id = _assetCatalogSystem!.GetResource(resourceKey);
_registry!.Register( _registry!.Register(
resourceKey,
_resourceLoadSystem!.GetOrRegisterResourceFactory<T>(id, duplicate), _resourceLoadSystem!.GetOrRegisterResourceFactory<T>(id, duplicate),
preload preload
); );

View File

@ -8,9 +8,19 @@ namespace GFramework.Core.Godot.system;
public interface IResourceFactorySystem : ISystem public interface IResourceFactorySystem : ISystem
{ {
/// <summary> /// <summary>
/// 获取指定类型T的资源创建函数 /// 根据指定键名获取指定类型T的资源创建函数
/// </summary> /// </summary>
/// <typeparam name="T">要获取创建函数的资源类型</typeparam> /// <typeparam name="T">要获取创建函数的资源类型</typeparam>
/// <param name="key">用于标识资源的键名</param>
/// <returns>返回一个创建T类型实例的函数委托</returns> /// <returns>返回一个创建T类型实例的函数委托</returns>
Func<T> Get<T>(); Func<T> GetFactory<T>(string key);
/// <summary>
/// 根据资产目录映射获取指定类型T的资源创建函数
/// </summary>
/// <typeparam name="T">要获取创建函数的资源类型</typeparam>
/// <param name="mapping">资产目录映射信息</param>
/// <returns>返回一个创建T类型实例的函数委托</returns>
Func<T> GetFactory<T>(AssetCatalog.AssetCatalogMapping mapping);
} }

View File

@ -19,13 +19,24 @@ public static class ResourceFactory
/// 执行与该条目关联的工厂方法 /// 执行与该条目关联的工厂方法
/// </summary> /// </summary>
void ExecuteFactory(); void ExecuteFactory();
/// <summary>
/// 获取资源类型
/// </summary>
Type ResourceType { get; }
/// <summary>
/// 获取资源键值
/// </summary>
string Key { get; }
} }
/// <summary> /// <summary>
/// 表示一个具体的资源工厂条目,实现 IPreloadableEntry 接口 /// 表示一个具体的资源工厂条目,实现 IPreloadableEntry 接口
/// </summary> /// </summary>
/// <typeparam name="T">资源类型</typeparam> /// <typeparam name="T">资源类型</typeparam>
private sealed class Entry<T>(Func<T> factory, bool preload) : IPreloadableEntry private sealed class Entry<T>(string key, Func<T> factory, bool preload) : IPreloadableEntry
{ {
/// <summary> /// <summary>
/// 获取用于创建资源的工厂函数 /// 获取用于创建资源的工厂函数
@ -41,8 +52,19 @@ public static class ResourceFactory
/// 执行工厂函数以创建资源实例 /// 执行工厂函数以创建资源实例
/// </summary> /// </summary>
public void ExecuteFactory() => Factory(); public void ExecuteFactory() => Factory();
/// <summary>
/// 获取资源的类型
/// </summary>
public Type ResourceType => typeof(T);
/// <summary>
/// 获取资源的键值
/// </summary>
public string Key { get; } = key;
} }
/// <summary> /// <summary>
/// 工厂注册表,管理所有已注册的资源工厂 /// 工厂注册表,管理所有已注册的资源工厂
/// </summary> /// </summary>
@ -51,34 +73,44 @@ public static class ResourceFactory
/// <summary> /// <summary>
/// 存储所有已注册的工厂函数,键为资源类型,值为对应的工厂条目对象 /// 存储所有已注册的工厂函数,键为资源类型,值为对应的工厂条目对象
/// </summary> /// </summary>
private readonly Dictionary<Type, object> _factories = new(); private readonly Dictionary<(Type type, string key), IPreloadableEntry> _factories = new();
/// <summary> /// <summary>
/// 注册指定类型的资源工厂 /// 注册指定类型的资源工厂
/// </summary> /// </summary>
/// <typeparam name="T">要注册的资源类型</typeparam> /// <typeparam name="T">要注册的资源类型</typeparam>
/// <param name="key">键</param>
/// <param name="factory">创建该类型资源的工厂函数</param> /// <param name="factory">创建该类型资源的工厂函数</param>
/// <param name="preload">是否需要预加载该资源默认为false</param> /// <param name="preload">是否需要预加载该资源默认为false</param>
public void Register<T>(Func<T> factory, bool preload = false) public void Register<T>(string key, Func<T> factory, bool preload = false)
{ {
_factories[typeof(T)] = new Entry<T>(factory, preload); if (string.IsNullOrWhiteSpace(key))
throw new ArgumentException("Resource key cannot be null or empty.", nameof(key));
var dictKey = (typeof(T), key);
_factories[dictKey] = new Entry<T>(key, factory, preload);
} }
/// <summary> /// <summary>
/// 解析并获取指定类型的工厂函数 /// 解析并获取指定类型的工厂函数
/// </summary> /// </summary>
/// <typeparam name="T">要获取工厂函数的资源类型</typeparam> /// <typeparam name="T">要获取工厂函数的资源类型</typeparam>
/// <param name="key">资源键</param>
/// <returns>指定类型的工厂函数</returns> /// <returns>指定类型的工厂函数</returns>
/// <exception cref="InvalidOperationException">当指定类型的工厂未注册时抛出异常</exception> /// <exception cref="InvalidOperationException">当指定类型的工厂未注册时抛出异常</exception>
public Func<T> Resolve<T>() public Func<T> ResolveFactory<T>(string key)
{ {
// 尝试从字典中查找对应类型的工厂条目 var dictKey = (typeof(T), key);
if (_factories.TryGetValue(typeof(T), out var obj)
&& obj is Entry<T> entry)
return entry.Factory;
// 若未找到则抛出异常 if (_factories.TryGetValue(dictKey, out var entry)
throw new InvalidOperationException($"Factory not registered: {typeof(T).Name}"); && entry is Entry<T> typed)
{
return typed.Factory;
}
throw new InvalidOperationException(
$"Factory not registered: {typeof(T).Name} with key '{key}'");
} }
/// <summary> /// <summary>
@ -87,14 +119,10 @@ public static class ResourceFactory
public void PreloadAll() public void PreloadAll()
{ {
// 遍历所有已注册的工厂 // 遍历所有已注册的工厂
foreach (var entry in _factories.Values) foreach (var entry in _factories.Values.Where(entry => entry.Preload))
{
// 检查当前条目是否支持预加载且被标记为需预加载
if (entry is IPreloadableEntry preloadable && preloadable.Preload)
{ {
// 执行其工厂方法进行预加载 // 执行其工厂方法进行预加载
preloadable.ExecuteFactory(); entry.ExecuteFactory();
}
} }
} }
} }