初学者,自用笔记
通过中央注册表/容器来获取服务对象的设计模式:业务代码不直接 new 依赖,而是向“服务定位器”按类型或键去 查询并取得所需服务实例
注册表
一个集中式的数据结构保存“名字/类型 → 对象/工厂/配置”的映射
静态注册表简单例子
public static class SkillFactoryRegistry
{
private static readonly Dictionary<SkillType, ISkillFactory> factories = new();
static SkillFactoryRegistry()
{
RegisterFactory(new SwapPositionSkillFactory());
RegisterFactory(new SwapScaleSkillFactory());
RegisterFactory(new SwapColliderSkillFactory());
RegisterFactory(new SwapTargetSkillFactory());
RegisterFactory(new SwapPlayerSkillFactory());
}
public static void RegisterFactory(ISkillFactory factory)
{
if (factory == null) return;
factories[factory.SupportType] = factory;
}
public static ISkillFactory GetFactory(SkillType type)
{
factories.TryGetValue(type, out var f);
return f;
}
}
DI注册表简单例子
public interface ISkillFactory
{
SkillType SupportType { get; }
ISkill Create();
}
public interface ISkillFactoryRegistry
{
ISkillFactory GetFactory(SkillType type);
bool TryGetFactory(SkillType type, out ISkillFactory factory);
}
public sealed class SkillFactoryRegistry : ISkillFactoryRegistry
{
private readonly IReadOnlyDictionary<SkillType, ISkillFactory> _map;
// DI 容器注入所有 ISkillFactory 的实现(VContainer 支持注入 IEnumerable<T>)
public SkillFactoryRegistry(IEnumerable<ISkillFactory> factories)
{
// 顺便做重复注册检测,避免“后注册覆盖前注册”导致隐蔽 bug
_map = factories
.GroupBy(f => f.SupportType)
.ToDictionary(
g => g.Key,
g =>
{
if (g.Count() > 1)
throw new InvalidOperationException($"Duplicate skill factory for type: {g.Key}");
return g.First();
});
}
public ISkillFactory GetFactory(SkillType type)
{
if (!_map.TryGetValue(type, out var f))
throw new KeyNotFoundException($"No skill factory registered for type: {type}");
return f;
}
public bool TryGetFactory(SkillType type, out ISkillFactory factory)
=> _map.TryGetValue(type, out factory);
}
bootstrapper(引导器)
程序启动时最先执行的一段“组装代码”
例如,处理单例生命周期问题
全局容器例子
1.RootLifetimeScope:搭架子+注册单例(注册表)
//游戏的全局根作用域 (Global Container)
//负责所有单例系统、基础服务的注册与生命周期管理
// LifetimeScope是vc在 Unity 场景/对象层级中创建并管理一个 DI 容器的作用域
public class RootLifetimeScope : LifetimeScope
{
// 利用 Unity 特性,在场景加载前自动创建 DI 根节点
// 这样就无需在场景里手动拖拽预制体,实现真正的 Zero-Scene-Dependency
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void AutoInitialize()
{
var go = new GameObject("[RootLifetimeScope]");
DontDestroyOnLoad(go);
go.AddComponent<RootLifetimeScope>();
}
protected override void Configure(IContainerBuilder builder)
{
Debug.Log("[RootScope] 开始注册全局服务...");
// 1. 注册核心基础服务 (以单例形式)
// 意味着任何地方请求 IManager,容器都会给同一个 Manager 实例
builder.Register<IManager, Manager>(Lifetime.Singleton);
// 2. 注册 Bootstrapper 启动器
// RegisterEntryPoint 会告诉 VContainer,构建完成后自动调用它的 StartAsync
builder.RegisterEntryPoint<GameBootstrapper>();
// 3. 构建回调:将 DI 容器桥接给静态 ServiceLocator
// 这样即使是不支持注入的纯静态类,也能通过 ServiceLocator.Get<IEventBus>() 拿到单例
builder.RegisterBuildCallback(resolver =>
{
ServiceLocator.Initialize(resolver);
});
}
}
2.GameBootstrapper:按顺序启动这些单例服务(编排启动流程)
//游戏全局启动器
//负责编排游戏启动时的各个异步流程(热更、读表、登录等)
public class GameBootstrapper : IAsyncStartable
{
//IAsyncStartable 用来让某个类在 DI 容器构建完成后,由 VContainer 自动调用一个异步的启动入口
private readonly IManager _Manager;//仅作示例
// 1. 通过构造函数,VContainer 会自动把这些核心系统注入进来
[Inject]
public GameBootstrapper(
IManager Manager)
{
_Manager = Manager;
}
// 2. 容器构建完毕后,自动触发 StartAsync
public async UniTask StartAsync(CancellationToken cancellation)
{
Debug.Log("[Bootstrapper] 游戏启动序列开始...");
// 初始化基础系统(如本地化、日志)
_Manager.Initialize();
// 初始化系统2
await _Manager.Initialize();
Debug.Log("[Bootstrapper] 资源更新完成.");
// 进入主界面 / 登录场景
EnterLoginScene();
}
private void EnterLoginScene()
{
Debug.Log("[Bootstrapper] 进入登录流程...");
// 触发全局事件,UI系统监听到后打开登录面板
}
}
3.ServiceLocator:把 DI 容器暴露成静态入口(给遗留/静态代码用)
//全局服务定位器(作为 DI 框架的静态桥接)
//仅供无法使用依赖注入的遗留代码或纯静态类使用
public static class ServiceLocator
{
//用于从 VContainer 容器里获取已经注册过的对象
private static IObjectResolver _container;
// 由 Bootstrapper 在框架构建完成后调用初始化
public static void Initialize(IObjectResolver container)
{
_container = container;
}
public static T Get<T>()
{
if (_container == null)
{
Debug.LogError($"[ServiceLocator] 容器未初始化,无法获取 {typeof(T).Name}");
return default;
}
return _container.Resolve<T>();
}
public static void Dispose()
{
_container = null;
}
}
场景(局部)容器例子
进入场景时注册,离开时注销
LifetimeScope
// 战斗场景的作用域容器
public class BattleLifetimeScope : LifetimeScope
{
// 如果场景里有已经摆好的物体(比如摄像机、UI画布),可以在面板上拖进来
[SerializeField] private Camera _battleCamera;
protected override void Configure(IContainerBuilder builder)
{
Debug.Log("[BattleScope] 正在注册战斗场景专属服务...");
// 1. 注册场景级单例逻辑 (Lifetime.Scoped)
//Lifetime.Scoped 表示在这个场景内它是单例,场景销毁它就销毁。
builder.RegisterEntryPoint<EnemyManager>(Lifetime.Scoped);
// 2. 注册场景启动器
builder.RegisterEntryPoint<BattleBootstrapper>();
// 3. 注册场景里实体的 MonoBehaviour 组件
// 这样其它非 Mono 的 C# 类也能直接 [Inject] 拿到这个摄像机
if (_battleCamera != null)
{
builder.RegisterComponent(_battleCamera);
}
}
}
Bootstrapper
// 战斗场景的入口点,负责编排战斗初始化流程
public class BattleBootstrapper : IAsyncStartable
{
private readonly EnemyManager _enemyManager;
private readonly IManager _globalManager;
// 它会在当前场景寻找 EnemyManager,同时去父节点(Root)寻找 IManager,一起注入进来
[Inject]
public BattleBootstrapper(EnemyManager enemyManager, IManager globalManager)
{
_enemyManager = enemyManager;// 仅作示例
_globalManager = globalManager;
}
public async UniTask StartAsync(CancellationToken cancellation)
{
Debug.Log("[BattleBootstrapper] 战斗场景开始初始化...");
// 1. 调用全局服务
_globalManager.Initialize();
// 2. 异步加载场景资源(假装耗时1秒)
await UniTask.Delay(1000, cancellationToken: cancellation);
// 3. 启动场景专属的管理器
_enemyManager.StartSpawning();// 自己写的方法
Debug.Log("[BattleBootstrapper] 战斗正式开始");
}
}

京公网安备 11010502036488号