架构演化学习考虑(4) --- IOC的学习知道
架构演化学习考虑(4)
IOC的学习知道
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的简略运用。
一般情况下,DIContainer会供给如下的API:
- 注册类型:Register<TSource,TTarget>
- 注入:Inject(object obj)
- 解析:Resolve()
注册和注入咱们在上面内容中运用了解了,而解析(Resolve)是什么意思呢?
Resolve实践上会依据类型回来实例。
那会发生疑问,回来的实例是每次都新建的仍是同一个实例呢?
在下面内容会逐渐解析。
咱们持续来聊IOCContainer的责任,正如上文所比方的那样,其责任便是办理依靠和注入依靠。经过类类型来办理依靠,给空引证赋值完结依靠注入。也便是说租房中介协助想要找房源的租客和挂号注册的房源之间树立联系,详细表现便是树立依靠。
这个中介手里掌握着租客和房源之间的对应联系,也能够对此依靠联系实行办理责任。所以一般的IOCContainer会用一个Dictionary<Type,object>来作为中心数据结构。
即依据Type能够得到Type的实例,依靠在代码中便是这样一个东西。而这个依靠不是指Type和object之间的相互依靠,而是说其结构自身便是一个依靠。
这儿比较绕,也便是说这儿的数据结构中存储的键值对元素自身便是依靠,是Inject(object obj) 中的obj的依靠。
即,object 类中有等待注入的null类型的索引对这种配对信息发生依靠。比方曩昔便是“租客名单”(object)对中介手中的(租客房源配对信息)有依靠,由于租客在配对信息中等级(object)才能够顺畅的和自已想要的房源进行配对。
不知道咱们这儿还能顺畅了解嘛!这便是IOCContainer中对依靠的办理办法。
没联系,咱们下面会看详细的实例。
咱们在看事例之前先简略聊一聊IOCContainer的强壮之处。
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办理即可。