一、IOC控制反转和DI依赖倒置
1、IOC框架核心原理是依赖倒置原则
使用这种思想方式,可以让我们无需关心对象的生成方式,只需要告诉容器我需要的对象即可,而告诉容器我需要对象的方式就叫做DI(依赖注入)。
今天主要想研究一下DI(依赖注入),这里我选了VContainer
地址:https://github.com/hadashiA/VContainer
文档地址:https://vcontainer.hadashikick.jp/
二、VContainer介绍
由于我们使用的是Unity,而主要的Mono不支持构造函数。所以我们这里选择注入方式主要是特性注入和方法注入
三、VContainer案例
(1)简单方法注入:
1、注册类型
public class GameLifetimeScope : LifetimeScope
{
protected override void Configure(IContainerBuilder builder)
{
builder.RegisterEntryPoint<ActorPresenter>();
}
}
2、方法注入
这里实现接口 IStartable和ITickable。它是不依赖于Mono的接口,因此性能上更好,另一方面,IStartable与Mono的Start,ITickable与Mono的Update都是相同的。
public class ActorPresenter : IStartable,ITickable
{
public void Start()
{
Debug.Log("Start ActorPresenter");
}
public void Tick()
{
Debug.Log("Update ActorPresenter");
}
}
(2)基础MVC功能:
Model层
public class UIModel
{
public void Hello()
{
Debug.Log("Hello World");
}
}
View层
public class UIView : MonoBehaviour
{
public Button button;
}
Control层
public class UIControl : IStartable
{
readonly UIModel _model;
readonly UIView _view;
public UIControl(UIModel model)
{
this._model = model;
}
public UIControl(UIModel model, UIView view)
{
this._model = model;
this._view = view;
}
public void Start()
{
_view.button.onClick.AddListener(() => _model.Hello());
}
}
通过这样做,我们成功地分离了领域控制/控制流/显示组件
在VContainter中,记得注册
public class GameLifetimeScope : LifetimeScope
{
public UIView helloScreen;
protected override void Configure(IContainerBuilder builder)
{
builder.RegisterEntryPoint<UIControl>();
builder.Register<UIModel>(Lifetime.Singleton);
builder.RegisterComponent(helloScreen);
}
}
(3)构造注入
构造函数里,只需要写一个需要依赖注入的函数,成员变量里就可以随时获得对象。如下例子ClassB构造函数的参数是ClassA,我们的classA变量就可以随时使用
class ClassB : IStartable,ITickable
{
readonly ClassA a;
public ClassB(ClassA a)
{
Debug.Log("ClassA构造函数注入");
this.a = a;
}
public void Start()
{
a.Start();
}
public void Tick()
{
a.Update();
}
}
class ClassA
{
public ClassA()
{
Debug.Log("ClassA构造");
}
public void Start()
{
Debug.Log("Start");
}
public void Update()
{
Debug.Log("Update");
}
}
public class GameLifetimeScope : LifetimeScope
{
//public UIView helloScreen;
protected override void Configure(IContainerBuilder builder)
{
builder.RegisterEntryPoint<ClassB>();
builder.Register<ClassA>(Lifetime.Singleton);
}
}
(4)方法注入(其他的和上边一样)
class ClassB : IStartable,ITickable
{
private ClassA a;
[Inject]
public void GetClassA(ClassA a)
{
Debug.Log("方法注入");
this.a = a;
}
public void Start()
{
a.Start();
}
public void Tick()
{
a.Update();
}
}
(5)字段/属性注入
class ClassB : IStartable,ITickable
{
[Inject]
private ClassA a;
public void Start()
{
a.Start();
}
public void Tick()
{
a.Update();
}
}
3、注册接口
public class GameLifetimeScople : LifetimeScope
{
protected override void Configure(IContainerBuilder builder)
{
//接口
builder.Register<ILogger, Logger>(Lifetime.Singleton);
builder.RegisterEntryPoint<LoggerEntryPoint>();
}
}
interface ILogger
{
void Log(string message);
}
public class Logger : ILogger
{
public void Log(string message)
{
Debug.Log(message);
}
}
public class LoggerEntryPoint : IStartable
{
[Inject] private ILogger logger;
public void Start()
{
logger.Log("哈哈哈");
}
}
4、注册工厂
public class GameLifetimeScople : LifetimeScope
{
protected override void Configure(IContainerBuilder builder)
{
//工厂
builder.RegisterEntryPoint<LoggerEntryPoint>();
builder.RegisterFactory<ILogger>(() => new Logger());
}
}
public class Logger : ILogger
{
public void Log(string message)
{
Debug.Log(message);
}
}
public class LoggerEntryPoint : IStartable
{
private ILogger logger;
[Inject]
public LoggerEntryPoint(Func<ILogger> loggerFactory)
{
logger = loggerFactory.Invoke();
}
public void Start()
{
logger.Log("哈哈哈");
}
}
带参
public class GameLifetimeScople : LifetimeScope
{
protected override void Configure(IContainerBuilder builder)
{
//工厂
builder.RegisterEntryPoint<LoggerEntryPoint>();
builder.RegisterFactory<string, ILogger>((value) => new Logger(value));
}
}
using VContainer.Unity;
using VContainer;
using UnityEngine;
using System;
public interface ILogger
{
void Log(string message);
}
public class Logger : ILogger
{
public Logger(string value)
{
Debug.Log($"实例化:{value}");
}
public void Log(string message)
{
Debug.Log(message);
}
}
public class LoggerEntryPoint : IStartable
{
[Inject]
public LoggerEntryPoint(Func<string, ILogger> loggerFactory)
{
loggerFactory.Invoke("第一个对象").Log("哈哈哈");
loggerFactory.Invoke("第二个对象").Log("啦啦啦");
}
public void Start()
{
}
}
4、RegisterInstance
protected override void Configure(IContainerBuilder builder)
{
builder.RegisterEntryPoint<LoggerEntryPoint>();
var logger = new Logger();
builder.RegisterInstance(logger);
}
public interface ILogger
{
void Log(string message);
}
public class Logger : ILogger
{
public void Log(string message)
{
Debug.Log(message);
}
}
public class LoggerEntryPoint : IStartable
{
public LoggerEntryPoint(Logger logger)
{
logger.Log("哈哈哈");
}
public void Start()
{
}
}
5、RegisterComponent
private TestMonoBehaviour testMonoBehaviour;
protected override void Configure(IContainerBuilder builder)
{
testMonoBehaviour = GetComponent<TestMonoBehaviour>();
builder.RegisterEntryPoint<LoggerEntryPoint>();
builder.RegisterComponent(testMonoBehaviour);
}
public class LoggerEntryPoint : IStartable
{
public LoggerEntryPoint(TestMonoBehaviour testMonoBehaviour)
{
testMonoBehaviour.Log("11111111");
}
public void Start()
{
}
}
6、不依赖EntryPoint
builder.Register<Logger>(Lifetime.Singleton);
builder.RegisterBuildCallback(objectResolver =>
{
objectResolver.Resolve<Logger>();
});
public class Logger
{
public Logger()
{
Debug.Log("hahhah");
}
}
如果经常这样使用,可以拓展
public static class ObjectResolverExtensions
{
public static RegistrationBuilder RegisterPlainEntryPoint<T>(this IContainerBuilder builder, Lifetime lifetime = Lifetime.Singleton)
{
builder.RegisterBuildCallback(objectResolver => objectResolver.Resolve<T>());
return builder.Register<T>(lifetime);
}
}
builder.RegisterPlainEntryPoint<Logger>();
public class Logger
{
public Logger()
{
Debug.Log("啦啦啦");
}
}
如果有此扩展方法,则可以使用一行调用与以前相同的 Register 和 RegisterBuildCallback。builder.RegisterPlainEntryPoint<EntryPointSample>();
7、处理EntryPoint的异常情况
builder.RegisterEntryPointExceptionHandler(e =>
{
Debug.LogException(e);
});
生命周期: