当前位置:   article > 正文

Unity——VContainer的依赖注入

vcontainer

一、IOC控制反转和DI依赖倒置

1、IOC框架核心原理是依赖倒置原则

C#设计模式的六大原则

使用这种思想方式,可以让我们无需关心对象的生成方式,只需要告诉容器我需要的对象即可,而告诉容器我需要对象的方式就叫做DI(依赖注入)

 今天主要想研究一下DI(依赖注入),这里我选了VContainer

地址:https://github.com/hadashiA/VContainer

文档地址:https://vcontainer.hadashikick.jp/

 二、VContainer介绍

 由于我们使用的是Unity,而主要的Mono不支持构造函数。所以我们这里选择注入方式主要是特性注入和方法注入

  三、VContainer案例

(1)简单方法注入:

1、注册类型

  1. public class GameLifetimeScope : LifetimeScope
  2. {
  3. protected override void Configure(IContainerBuilder builder)
  4. {
  5. builder.RegisterEntryPoint<ActorPresenter>();
  6. }
  7. }

2、方法注入

这里实现接口 IStartableITickable。它是不依赖于Mono的接口,因此性能上更好,另一方面,IStartable与Mono的Start,ITickable与Mono的Update都是相同的。

  1. public class ActorPresenter : IStartable,ITickable
  2. {
  3. public void Start()
  4. {
  5. Debug.Log("Start ActorPresenter");
  6. }
  7. public void Tick()
  8. {
  9. Debug.Log("Update ActorPresenter");
  10. }
  11. }

(2)基础MVC功能:

Model层

  1. public class UIModel
  2. {
  3. public void Hello()
  4. {
  5. Debug.Log("Hello World");
  6. }
  7. }

View层

  1. public class UIView : MonoBehaviour
  2. {
  3. public Button button;
  4. }

 Control层

  1. public class UIControl : IStartable
  2. {
  3. readonly UIModel _model;
  4. readonly UIView _view;
  5. public UIControl(UIModel model)
  6. {
  7. this._model = model;
  8. }
  9. public UIControl(UIModel model, UIView view)
  10. {
  11. this._model = model;
  12. this._view = view;
  13. }
  14. public void Start()
  15. {
  16. _view.button.onClick.AddListener(() => _model.Hello());
  17. }
  18. }

通过这样做,我们成功地分离了领域控制/控制流/显示组件

在VContainter中,记得注册

  1. public class GameLifetimeScope : LifetimeScope
  2. {
  3. public UIView helloScreen;
  4. protected override void Configure(IContainerBuilder builder)
  5. {
  6. builder.RegisterEntryPoint<UIControl>();
  7. builder.Register<UIModel>(Lifetime.Singleton);
  8. builder.RegisterComponent(helloScreen);
  9. }
  10. }

(3)构造注入

        构造函数里,只需要写一个需要依赖注入的函数,成员变量里就可以随时获得对象。如下例子ClassB构造函数的参数是ClassA,我们的classA变量就可以随时使用

  1. class ClassB : IStartable,ITickable
  2. {
  3. readonly ClassA a;
  4. public ClassB(ClassA a)
  5. {
  6. Debug.Log("ClassA构造函数注入");
  7. this.a = a;
  8. }
  9. public void Start()
  10. {
  11. a.Start();
  12. }
  13. public void Tick()
  14. {
  15. a.Update();
  16. }
  17. }
  1. class ClassA
  2. {
  3. public ClassA()
  4. {
  5. Debug.Log("ClassA构造");
  6. }
  7. public void Start()
  8. {
  9. Debug.Log("Start");
  10. }
  11. public void Update()
  12. {
  13. Debug.Log("Update");
  14. }
  15. }
  1. public class GameLifetimeScope : LifetimeScope
  2. {
  3. //public UIView helloScreen;
  4. protected override void Configure(IContainerBuilder builder)
  5. {
  6. builder.RegisterEntryPoint<ClassB>();
  7. builder.Register<ClassA>(Lifetime.Singleton);
  8. }
  9. }
(4)方法注入(其他的和上边一样)
  1. class ClassB : IStartable,ITickable
  2. {
  3. private ClassA a;
  4. [Inject]
  5. public void GetClassA(ClassA a)
  6. {
  7. Debug.Log("方法注入");
  8. this.a = a;
  9. }
  10. public void Start()
  11. {
  12. a.Start();
  13. }
  14. public void Tick()
  15. {
  16. a.Update();
  17. }
  18. }
(5)字段/属性注入
  1. class ClassB : IStartable,ITickable
  2. {
  3. [Inject]
  4. private ClassA a;
  5. public void Start()
  6. {
  7. a.Start();
  8. }
  9. public void Tick()
  10. {
  11. a.Update();
  12. }
  13. }

3、注册接口

  1. public class GameLifetimeScople : LifetimeScope
  2. {
  3. protected override void Configure(IContainerBuilder builder)
  4. {
  5. //接口
  6. builder.Register<ILogger, Logger>(Lifetime.Singleton);
  7. builder.RegisterEntryPoint<LoggerEntryPoint>();
  8. }
  9. }
  1. interface ILogger
  2. {
  3. void Log(string message);
  4. }
  5. public class Logger : ILogger
  6. {
  7. public void Log(string message)
  8. {
  9. Debug.Log(message);
  10. }
  11. }
  12. public class LoggerEntryPoint : IStartable
  13. {
  14. [Inject] private ILogger logger;
  15. public void Start()
  16. {
  17. logger.Log("哈哈哈");
  18. }
  19. }

4、注册工厂

  1. public class GameLifetimeScople : LifetimeScope
  2. {
  3. protected override void Configure(IContainerBuilder builder)
  4. {
  5. //工厂
  6. builder.RegisterEntryPoint<LoggerEntryPoint>();
  7. builder.RegisterFactory<ILogger>(() => new Logger());
  8. }
  9. }
  1. public class Logger : ILogger
  2. {
  3. public void Log(string message)
  4. {
  5. Debug.Log(message);
  6. }
  7. }
  8. public class LoggerEntryPoint : IStartable
  9. {
  10. private ILogger logger;
  11. [Inject]
  12. public LoggerEntryPoint(Func<ILogger> loggerFactory)
  13. {
  14. logger = loggerFactory.Invoke();
  15. }
  16. public void Start()
  17. {
  18. logger.Log("哈哈哈");
  19. }
  20. }

带参

  1. public class GameLifetimeScople : LifetimeScope
  2. {
  3. protected override void Configure(IContainerBuilder builder)
  4. {
  5. //工厂
  6. builder.RegisterEntryPoint<LoggerEntryPoint>();
  7. builder.RegisterFactory<string, ILogger>((value) => new Logger(value));
  8. }
  9. }
  1. using VContainer.Unity;
  2. using VContainer;
  3. using UnityEngine;
  4. using System;
  5. public interface ILogger
  6. {
  7. void Log(string message);
  8. }
  9. public class Logger : ILogger
  10. {
  11. public Logger(string value)
  12. {
  13. Debug.Log($"实例化:{value}");
  14. }
  15. public void Log(string message)
  16. {
  17. Debug.Log(message);
  18. }
  19. }
  20. public class LoggerEntryPoint : IStartable
  21. {
  22. [Inject]
  23. public LoggerEntryPoint(Func<string, ILogger> loggerFactory)
  24. {
  25. loggerFactory.Invoke("第一个对象").Log("哈哈哈");
  26. loggerFactory.Invoke("第二个对象").Log("啦啦啦");
  27. }
  28. public void Start()
  29. {
  30. }
  31. }

4、RegisterInstance

  1. protected override void Configure(IContainerBuilder builder)
  2. {
  3. builder.RegisterEntryPoint<LoggerEntryPoint>();
  4. var logger = new Logger();
  5. builder.RegisterInstance(logger);
  6. }
  1. public interface ILogger
  2. {
  3. void Log(string message);
  4. }
  5. public class Logger : ILogger
  6. {
  7. public void Log(string message)
  8. {
  9. Debug.Log(message);
  10. }
  11. }
  12. public class LoggerEntryPoint : IStartable
  13. {
  14. public LoggerEntryPoint(Logger logger)
  15. {
  16. logger.Log("哈哈哈");
  17. }
  18. public void Start()
  19. {
  20. }
  21. }

5、RegisterComponent

  1. private TestMonoBehaviour testMonoBehaviour;
  2. protected override void Configure(IContainerBuilder builder)
  3. {
  4. testMonoBehaviour = GetComponent<TestMonoBehaviour>();
  5. builder.RegisterEntryPoint<LoggerEntryPoint>();
  6. builder.RegisterComponent(testMonoBehaviour);
  7. }
  1. public class LoggerEntryPoint : IStartable
  2. {
  3. public LoggerEntryPoint(TestMonoBehaviour testMonoBehaviour)
  4. {
  5. testMonoBehaviour.Log("11111111");
  6. }
  7. public void Start()
  8. {
  9. }
  10. }

6、不依赖EntryPoint

  1. builder.Register<Logger>(Lifetime.Singleton);
  2. builder.RegisterBuildCallback(objectResolver =>
  3. {
  4. objectResolver.Resolve<Logger>();
  5. });
  1. public class Logger
  2. {
  3. public Logger()
  4. {
  5. Debug.Log("hahhah");
  6. }
  7. }

如果经常这样使用,可以拓展

  1. public static class ObjectResolverExtensions
  2. {
  3. public static RegistrationBuilder RegisterPlainEntryPoint<T>(this IContainerBuilder builder, Lifetime lifetime = Lifetime.Singleton)
  4. {
  5. builder.RegisterBuildCallback(objectResolver => objectResolver.Resolve<T>());
  6. return builder.Register<T>(lifetime);
  7. }
  8. }
 builder.RegisterPlainEntryPoint<Logger>();
  1. public class Logger
  2. {
  3. public Logger()
  4. {
  5. Debug.Log("啦啦啦");
  6. }
  7. }

如果有此扩展方法,则可以使用一行调用与以前相同的 Register 和 RegisterBuildCallback。builder.RegisterPlainEntryPoint<EntryPointSample>();

7、处理EntryPoint的异常情况

  1. builder.RegisterEntryPointExceptionHandler(e =>
  2. {
  3. Debug.LogException(e);
  4. });

生命周期:

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号