如何基于运行时参数绑定Factory对象的派生类(Zenject)
可行方案实现运行时动态绑定角色派生类
你当前的核心问题是CharacterInstaller在初始化阶段就完成了依赖绑定,无法响应运行时传入的角色类型参数。下面提供几种针对Zenject+对象池场景的解决方案,核心思路是将依赖绑定时机推迟到角色实例创建的运行时刻:
方案一:角色内部根据类型动态初始化依赖
修改Character类,通过注入的容器实例,在对象从池取出时根据类型解析对应的攻击系统:
public enum 角色类型 { 近战, 远程, } public class Character : MonoBehaviour, IPoolable<IMemoryPool> { private IAttackSystem _攻击系统; private DiContainer _容器; private 角色类型 _当前类型; private IMemoryPool _对象池; [Inject] public void 初始化容器(DiContainer container) { _容器 = container; } // 对象池取出时调用,传入运行时类型参数 public void 生成初始化(角色类型 类型) { _当前类型 = 类型; 创建对应攻击系统(); } private void 创建对应攻击系统() { switch (_当前类型) { case 角色类型.近战: _攻击系统 = _容器.Instantiate<MeleeAttackSystem>(); break; case 角色类型.远程: _攻击系统 = _容器.Instantiate<RangedAttackSystem>(); break; } } public void 回收清理() { if (_攻击系统 is IDisposable 可释放资源) { 可释放资源.Dispose(); } _攻击系统 = null; _对象池.Despawn(this); } public void 设置对象池(IMemoryPool pool) { _对象池 = pool; } } // 自定义带类型参数的角色工厂 public class 角色工厂 : PlaceholderFactory<角色类型, Character> { } public class 角色创建器 { private 角色工厂 _工厂; [Inject] public 角色创建器(角色工厂 factory) { _工厂 = factory; } public void 创建近战角色() { _工厂.Create(角色类型.近战); } public void 创建远程角色() { _工厂.Create(角色类型.远程); } } public class CharacterInstaller : MonoInstaller { public GameObject 角色预制体; public override void InstallBindings() { // 绑定角色对象池 Container.BindMemoryPool<Character, Character.Pool>() .WithInitialSize(5) .FromComponentInNewPrefab(角色预制体) .UnderTransformGroup("角色对象组"); // 绑定自定义工厂 Container.Bind<角色工厂>().AsSingle(); // 提前注册攻击系统实现,方便动态解析 Container.Bind<MeleeAttackSystem>().AsTransient(); Container.Bind<RangedAttackSystem>().AsTransient(); } }
方案二:用子容器实现类型专属依赖绑定
为不同类型的角色预制体创建独立子容器,每个子容器绑定对应类型的依赖:
public enum 角色类型 { 近战, 远程, } public class CharacterInstaller : MonoInstaller { public GameObject 近战角色预制体; public GameObject 远程角色预制体体; public override void InstallBindings() { // 为近战角色绑定子容器及专属依赖 Container.BindSubContainerForPrefab<Character>(近战角色预制体) .ByInstalling<近战角色子容器安装器>(); // 为远程角色绑定子容器及专属依赖 Container.BindSubContainerForPrefab<Character>(远程角色预制体) .ByInstalling<远程角色子容器安装器>(); // 绑定根据类型选择预制体的工厂 Container.BindFactory<角色类型, Character, Character.Factory>() .FromFactory<按类型选预制体工厂>(); } } // 自定义工厂:根据运行时类型选择对应预制体 public class 按类型选预制体工厂 : IFactory<角色类型, Character> { private readonly DiContainer _容器; private readonly GameObject _近战预制体; private readonly GameObject _远程预制体; [Inject] public 按类型选预制体工厂(DiContainer container, [Inject(Id = "近战角色")] GameObject 近战预制体, [Inject(Id = "远程角色")] GameObject 远程预制体) { _容器 = container; _近战预制体 = 近战预制体; _远程预制体 = 远程预制体; } public Character Create(角色类型 类型) { var 目标预制体 = 类型 == 角色类型.近战 ? _近战预制体 : _远程预制体; return _容器.InstantiateComponent<Character>(目标预制体); } } // 近战角色专属依赖安装器 public class 近战角色子容器安装器 : MonoInstaller { public override void InstallBindings() { Container.Bind<IAttackSystem>().To<MeleeAttackSystem>().AsSingle(); } } // 远程角色专属依赖安装器 public class 远程角色子容器安装器 : MonoInstaller { public override void InstallBindings() { Container.Bind<IAttackSystem>().To<RangedAttackSystem>().AsSingle(); } }
方案三:通过带参数工厂直接传入依赖
在创建角色时,先解析对应类型的攻击系统,再作为参数传入角色实例:
public class Character : MonoBehaviour, IPoolable<IMemoryPool> { private IAttackSystem _攻击系统; private IMemoryPool _对象池; // 初始化时直接传入已解析的攻击系统 public void 初始化(IAttackSystem 攻击系统) { _攻击系统 = 攻击系统; } public void 回收清理() { if (_攻击系统 is IDisposable 可释放资源) { 可释放资源.Dispose(); } _攻击系统 = null; _对象池.Despawn(this); } public void 设置对象池(IMemoryPool pool) { _对象池 = pool; } } // 带攻击系统参数的角色工厂 public class 角色工厂 : PlaceholderFactory<IAttackSystem, Character> { } public class 角色创建器 { private 角色工厂 _工厂; private DiContainer _容器; [Inject] public 角色创建器(角色工厂 factory, DiContainer container) { _工厂 = factory; _容器 = container; } public void 创建近战角色() { var 近战攻击系统 = _容器.Instantiate<MeleeAttackSystem>(); _工厂.Create(近战攻击系统); } public void 创建远程角色() { var 远程攻击系统 = _容器.Instantiate<RangedAttackSystem>(); _工厂.Create(远程攻击系统); } } public class CharacterInstaller : MonoInstaller { public GameObject 角色预制体; public override void InstallBindings() { Container.BindMemoryPool<Character, Character.Pool>() .WithInitialSize(5) .FromComponentInNewPrefab(角色预制体) .UnderTransformGroup("角色对象组"); Container.Bind<角色工厂>().AsSingle(); Container.Bind<MeleeAttackSystem>().AsTransient(); Container.Bind<RangedAttackSystem>().AsTransient(); } }
内容的提问来源于stack exchange,提问作者Enescan BEKTAŞ
相关产品推荐
相关产品推荐

