架构演化学习思考(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的简单使用。
一般情况下,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管理即可。
架构演化学习思考(4) --- IOC的学习认识的更多相关文章
- spring学习(01)之IOC
spring学习(01)之IOC IOC:控制反转——Spring通过一种称作控制反转(IOC)的技术促进了低耦合.当应用了IOC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创 ...
- Unity(IOC)学习笔记
原文:Unity(IOC)学习笔记 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/m0_37591671/article/details/79432 ...
- 记一次Jquery学习引发的学习思考
学习廖雪峰Jquery的教程关于表单的操作时,被最后的习题给困住了,在一番思索后无奈地决定去看博客评论下的答案,却发现自己看不懂,遂以为是对Jquery的了解还不够深,于是便在网上疯狂搜索关于Jque ...
- [转]Android App整体架构设计的思考
1. 架构设计的目的 对程序进行架构设计的原因,归根到底是为了提高生产力.通过设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合.这样做的好处是使得程序在开发的过程中,开发人员只需要专注于一点, ...
- Java 学习路线以及各阶段学习书籍,博文,视频的分享
感谢: 感谢每一个打开这篇文章的人,听我在这里瞎扯!至于我为什么会有闲情写这篇文章呢?因为我每天想的是为什么要给我这样的需求,背后的人性是什么,我能再做些什么能让他更好.久而久之,我也稍微有了些自己的 ...
- 关于ASP.NET MVC+Repository+Service架构的一些思考
看了一些ASP.NET MVC开源项目后的一些想法,关于ASP.NET MVC+Repository+Service架构的一些思考 最近在学习ASP.NET MVC 2.0的一些开源项目,发现这些项目 ...
- [深度学习]DEEP LEARNING(深度学习)学习笔记整理
转载于博客http://blog.csdn.net/zouxy09 一.概述 Artificial Intelligence,也就是人工智能,就像长生不老和星际漫游一样,是人类最美好的梦想之中的一个. ...
- 【学习博客】Python学习初体验
本周是正式开始学习Python的第一周.很久不写代码了,毕业第5年了,期间几乎没怎么动过手.这段时间比较规律.密集的学习又让我找回了当时的感觉,还不算陌生,我挺喜欢的这种能实实在在看到自己知识增长的状 ...
- Api容器在应用架构演化中的用途
单层架构 在最开始编程的时候相信大家都写过下面这种架构,界面代码,业务代码,数据库连接全部在工程面完成.当然这种架构在处理很小的程序的时候依然有生命力 两层架构 后来我们发现数据访问的代码大量重复,应 ...
- ArchSummit分享 | 高德地图App架构演化与实践
讲师介绍 郝仁杰,高德地图无线开发专家.在7月13日落幕的2019年ArchSummit峰会上就高德地图近几年的App架构演化和实践进行了分享. 背景概述 高德是国内领先的数字地图内容.导航和位置服务 ...
随机推荐
- windows 安装mysql 非常之详细
安装 1.下载安装包 2.解压包 3.文件夹内创建my.ini配置文件,并添加内容 # For advice on how to change settings please see # http: ...
- 如何将本地的项目,上传到github
操作步骤: 1.github,创建一个仓库,复制仓库的地址 2.在要上传文件的目录,点击选择git bash here 3.输入[git clone],粘贴刚复制的仓库地址,clone成功后,会将仓库 ...
- 实验10.3层vlan互通实验
# 实验10.三层Vlan互通实验 本实验是跨vlan路由的第二种形式,比第一种形式更常见常用一些. 需要用到三层交换机. 实验组 交换机配置 不同于以往,本次的交换机使用了三层交换的功能 SW vl ...
- 配置h5py、netCDF4库的方法:Anaconda环境
本文介绍基于Anaconda环境,下载并安装Python中h5py与netCDF4这两个模块的方法. 在Python语言中,h5py与netCDF4这两个模块是与遥感图像处理.地学分析等GIS ...
- [UG 二次开发 python] 生成略缩图并保存
保存到零件同名的文件夹下,名称相同,类型是 jpg 用到 numpy,PIL,cv2 blockstyler 文件略 # nx: threaded __version__ = "0.0.1& ...
- Spring AOP面向切面编程核心概念
横切关注点 对那些方法进行拦截,拦截后怎么处理,这些就叫横切关注点 比如:权限认证.日志.事务 通知 Advice 在特定的切入点上执行的增强处理,有5种通知 用途:记录日志.控制事务.提前编写好通用 ...
- HBase 在统一内容平台业务的优化实践
作者:来自 vivo 互联网服务器团队-Leng Jianyu.Huang Haitao HBase是一款开源高可靠性.扩展性.高性能和灵活性的分布式非关系型数据库,本文围绕数据库选型以及使用HBas ...
- [oeasy]python0078_变量部分总结_variable_summary
删除变量 回忆上次内容 上次研究了变量的死 有生就有死 原本的死是在程序退出的时候自动执行的 也可以手动给变量执行死刑 del del(a)之后 dir()就无法在当前作用域(scope)内观 ...
- [oeasy]python0027_整合程序_延迟输出时间_整合两个py程序
整合程序 回忆上次内容 通过搜索发现 time中有函数可以延迟 time.sleep(1) 还可以让程序无限循环 while True: 现在需要两个程序的整合 循环延迟输出 时间输出 编辑 ...
- oeasy教您玩转vim - 89 - # 高亮细节Highlight
高亮细节 highight 回忆 这个自动命令 autocmd 还是很方便的 打开时.保存时就会有自动执行的操作 自动命令有这么几大元素 {event} 触发事件 {pattern} 文件模式 { ...