架构演化学习思考(4) --- IOC的学习认识
架构演化学习思考(4)
IOC的学习认识[1]
IOC相关概念认识
什么是IOC?
IOC全称为 Inversion Of Control ,即控制反转。它是一种控制思想,可以解释为类和类之间的依赖关系不再由代码直接控制,而是通过容器来控制和配置实现。
控制反转?那么什么是正传? 反转有啥好处?IOC到底是啥?
好,那就开始逐步认识和了解吧~
既然是一种思想,那就从它的常见实现方式DI来入手。
DI
DI,即 Dependence Injection,依赖注入,它是IOC的一种实现。
依赖这个概念我们在第一篇文章中解释过,它是一种对象/引用的持有关系。
最简单的单项依赖:
A对B产生依赖关系。
public class A
{
public B b = new B();
}
那么注入又是什么?
注入是建立依赖关系的过程。
public class A
{
//持有B的空引用
public B b =null;
}
public class B {}
void Main()
{
var a = new A();
var b = new B();
//建立AB之间的依赖关系
//即注入
a.b = b;
}
也就是说,A和B建立依赖的过程便是注入。因为注入操作。使的A中b引用不再为空,而是直接拿到B对象的引用。
到此我们认识了”依赖注入“的操作,就是帮助建立对象与对象之间的依赖关系,让A对象完成持有B对象引用的操作。
IOCContainer的使用
DI的具体实现离不开DI容器,DI容器有时候也称为IOC容器,通过此容器来完成依赖注入的工作。来看一下IOCContainer的使用。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using QFramework
namespace IOCContainerExample
{
public class A
{
public void Say()
{
Debug.Log("我是A" + this.GetHashCode());
}
}
public class IOCExample: MonoBehaviour
{
//添加注入标记
[Inject]
public A a {get;set;}
void Start()
{
//创建容器实例
var container = new QFrameworkContainer();
//注册需要注入的类型
container.Register<A>();
//进行依赖注入
//会自动查找 Inject Atrribute的对象
container.Inject(this);
//注入之后可以使用了
a.Say();
}
}
}
使用IOCContainer来进行依赖注入,先给容器注册相关的类型,然后标记要获取对象的空引用,之后调用容器的Inject方法完成依赖注入。
这个这个容器可以理解为一个”租房中介“,想要出租房屋的房东们向中介进行”Register“注册,当调用Inject()方法时候,中介会根据租客( [Inject]标记的空引用)的租房类型来匹配合适的房源,完成租客找房源的目的,帮助租客完成对房子的依赖。
这就是IOCContainer的简单使用。
这样就解决了单例结构无法表达层级问题,但是同时也失去了单例带来的种种好处
,但是同样失去了单例的种种好处,易扩展。
因为现在单例结果对底层的模块产生了依赖关系,当拓展功能模块时候要考虑对底层模块的依赖关系。
那么IOCContainer的强大之处体现出来,帮助管理依赖关系。
依赖管理
我们回过头来再看依赖管理相关内容,依赖注入的时机和位置是一个需要关注的问题。
public class ModuleA
{
public ModuleB moduleB;
}
public class ModuleB
{
}
来看一个待注入的依赖,依赖注入我们可以再ModuleA内部进行:
public class ModuleA
{
public ModuleB moduleB = new ModuleB();
}
但是如果MoudleB是公用的呢?在内部创建显然就不太合适了,因为这里是一个模块,不是简单的一个对象。
那就在外部创建对象:
void main()
{
var moduleA = new ModuleA;
mouduleA.moudleB = new MoudleB();
}
那在外部注入的依赖在模块内部使用时候就得需要知道依赖到底注入没有?
在哪里注入的?我可不可以直接用?
public class ModuleA
{
public ModuleB moduleB;
/*
..。其它代码逻辑
*/
void someFunc()
{
//需要使用moduleB
//需要知道moduleB到底有没有值?在哪里获取到的?
moduleB.XXX
}
}
所以这就不得不考虑依赖的创建过程了。
而使用单例,那就没有这个问题。
public class ModuleA
{
void someFunc()
{
//直接使用单例
moduleB.Instance.DoSomething();
}
}
现在该IOCContainer登场了。
是的,IOCContainer的职责就是注入依赖、管理依赖。
使用IOCContainer管理依赖
public class ModuleA
{
[Inject]
public ModuleB moduleB;
void something()
{
//放心使用 不用考虑是否为空
moduleB.DoSomeThing();
}
}
在启动程序的时候,统一注册依赖:
public static QFrameworkContainer Container {get; set;}
void Main()
{
Container = new Container();
Container.Register<MoudleB>();
}
在MoudleA的构造函数中注入依赖:
public class ModuleA
{
[Inject]
public ModuleB moduleB;
//构造函数
public MoudleA()
{
//注入依赖
Global.ContainerInject(this);
}
void something()
{
//放心使用 不用考虑是否为空
moduleB.DoSomeThing();
}
}
这样使用IOCContainer对各种依赖进行管理其模块内容变得更佳清晰:
放心使用依赖内容,依赖管理和注入交给IOCContainer管理即可。