.wj_nav { display: inline-block; width: 100%; margin-bottom: 0.375rem }
.wj_nav span { display: inline-block; margin-right: 0.375rem; color: rgba(102, 102, 102, 1) }
.wj_nav a, .wj_nav a:link, .wj_nav a:visited { color: rgba(51, 51, 51, 1); text-decoration: underline }
.wj_nav a:hover { color: rgba(255, 102, 0, 1); text-decoration: none }
.wj_title_1 { display: inline-block; width: 100%; margin-bottom: 1rem; border-left: 0.375rem solid rgba(255, 102, 0, 1); background-color: rgba(232, 232, 232, 1); font-size: 1.5rem; padding: 0.3125rem 0.625rem }
.wj_title_2 { display: inline-block; width: 100%; font-size: 1.25rem; font-weight: bold; margin-bottom: 1rem }
.wj_title_3 { display: inline-block; width: 100%; font-size: 1rem; font-weight: bold; margin-bottom: 1rem }
.wj_cont { line-height: 180%; margin-bottom: 1rem; font-size: 1rem }
.wj_img { display: inline-block; width: 100%; margin-bottom: 1rem }
.wj_code { margin-top: 0 !important; margin-bottom: 1rem !important; font-size: 0.875rem !important }
.wj_table { border: 1px solid rgba(255, 136, 56, 1); border-collapse: collapse; margin-bottom: 1rem }
.wj_table tr { display: table-row; vertical-align: inherit }
.wj_table tr th { display: table-cell; vertical-align: inherit; font-weight: normal; border: 1px solid rgba(255, 136, 56, 1); padding: 5px 10px; background-color: rgba(255, 102, 0, 1); color: rgba(255, 255, 255, 1); text-align: left }
.wj_table tr td { display: table-cell; vertical-align: inherit; border: 1px solid rgba(255, 136, 56, 1); padding: 0.3125rem 0.625rem; background-color: rgba(255, 255, 255, 1); text-align: left }
.wj_link, .wj_link:link, .wj_link:visited { color: rgba(51, 51, 51, 1); text-decoration: underline }
.wj_link:hover, .wj_link:active { color: rgba(255, 102, 0, 1) }
.wj_watermark, .wj_watermark :link, .wj_watermark :visited { color: rgba(255, 255, 255, 1) !important }
.wj_watermark :hover, .wj_link:active { color: rgba(255, 255, 255, 1) !important }
.wj_important { font-weight: bold; color: rgba(255, 102, 0, 1) }

导航

1前言

2什么是依赖注入与控制反转

2.1控制反转

2.2依赖注入

3为什么要使用依赖注入与控制反转

3.1解耦

3.2单元测试

4IoC容器

5结束语

1 前言

依赖注入(DI)与控制反转(IoC)可能是一些开发小伙伴耳熟但又不能详的两个词,经常看到它们的名字,但又不理解。这两个词来源于英文直译,看似高深莫测,其实非常简单,并且在一些开发场景中扮演着不可或缺的角色,比如单元测试离不开依赖注入,IoC容器是插件框架的最佳拍档等,本文尝试以最简单的方式阐述这两种思想在开发中的应用。文章来源:https://www.wubayue.com

2 什么是依赖注入与控制反转

2.1 控制反转

在解释控制反转前,首先需要理解什么是“正转”:A依赖于B,并且A掌控B的创建销毁,此时A控制了B,即为“正转”。

当B的创建销毁在A之外完成,B脱离了A的控制,称之为控制反转(IoC:Invertion of Control)。

public class A
{
    private B _b;
    public A()
    {
        // 因为A掌控B的创建,因此A控制了B,此为“正转”
        _b = new B();
    }
}

2.2 依赖注入

对象之间的依赖不再由内部创建,而是由外部传递,称之为依赖注入(DI:Dependency Injection)。

控制反转是设计思想,依赖注入是实现手段。两者缺一不可:

public class A
{
    private B _b;     // B由外部注入,称之为依赖注入
    public A(B b)
    {
        // B由外部创建,脱离了A的控制,称之为控制反转
        _b = b;
    }
}

如上代码示例的是构造函数注入,另一种常见的依赖注入方式是属性注入:

public class A
{
    public B B { get; set; }
} void main()
{
    A a = new A();
    B b = new B();
    // 属性注入
    a.B = b;
}

3 为什么要使用依赖注入与控制反转

3.1 解耦

在软件行业,有一条黄金法则叫“高内聚,低耦合”。耦合表示使用(或称为依赖),比如B使用了A,即B耦合了A,只要类的数量一多,类之间千丝万缕的耦合关系会成为巨大挑战,高内聚就是把相同的功能放在一起,这样类之间的耦合关系就会减少,通过提升内聚来减少类之间的耦合是一种常见的解耦方式。如上图,C依赖B,B依赖A,原本是两级依赖关系,通过将B中的部分功能向A内聚(前提是这部分功能原本就具有相关性),实现了B、C都依赖于A的一级依赖关系,B、C之间完成了解耦。

解耦除了完全消除依赖关系以外,另一种方式是将紧耦合转换为松耦合。先解释一下松紧耦合的概念,我们打开电脑机箱找到主机板上的南北桥芯片,可以看到它们是完全焊接在主板上的,这种不可替换的连接即为紧耦合;再找到内存条,发现它们可以拆卸并更换为其它品牌,这种可替换的连接即为松耦合。大部分时候,在软件设计开发时都应使用松散耦合,而依赖注入就是实现松散耦合非常好的一种方式。

如果我们再稍思考一下,主板上的内存条为什么能安装不同的品牌?原因是有相关技术标准,比如长宽尺寸,针脚数量,通信标准等,不同的内存条厂商,只要遵循标准生产出来的内存条就能安装到同一块主板上。在软件开发中,让主板支持不同厂商的内存条称之为可扩展性,定义内存条接口标准称之为抽象,根据标准生产内存条称之为面向抽象编程(或面向接口编程)。因此为了使软件模块具备更好的扩展性,除了使用依赖注入,还应注入抽象而非具体。

3.2 单元测试

不了解单元测试的小伙伴可先阅读我的另一篇文章《单元测试从入门到精通》。在单元测试中如果没有依赖注入,几乎寸步难行,通过简单的代码来示例:

难以测试的代码:

// 被测对象
public class House
{
    private Bedroom _bedroom;
    House() 
    { 
        // 内部构造协作对象,难以被测试。
        _bedroom = new Bedroom(); 
    }
    // ...
} // 测试用例
public void TestThisIsReallyHard()
{
    House house = new House();
    // 无法在测试过程中对Bedroom进行属性赋值、行为方法调用等,测试寸步难行
    // ...
}

易于测试的代码:

// 被测对象
public class House
{
    private Bedroom _bedroom;
    // 注入协作对象,可测试性好。
    House(Bedroom b) 
    { 
        _bedroom = b;
    }
    // ...
} // 测试用例
public void TestThisIsEasyAndFlexible()
{
    // Bedroom对象在掌控之中,易于测试
    Bedroom bedroom = new Bedroom();
    House house = new House(bedroom);
    // ...
}

4 Ioc容器

在稍复杂的软件产品中,通常会遇到两个关于对象的问题:一是对象的数量众多,如何统一对它们进行管理,比如统一管理对象的创建销毁过程,每个对象的生命周期;二是对象之间可能存在多重复杂的依赖关系,如何对这些依赖关系进行管理,比如谁先创建谁后创建,被依赖的对象如何注入依赖对象等。

针对如上两个问题的解决方案就是IoC容器(IoC Container),IoC容器是一个对象管理器,它统一管理对象的创建销毁过程、生命周期、依赖关系,以及提供自动注入、根据配置创建对象等一系列便捷功能。如下代码使用 Autofac(C#开源IoC容器)进行了简单示例:

// 使用开源IoC容器Autofac
using Autofac; namespace AutofacDemo
{
    class A
    { }     class B
    {
        A _a;
        // 只需要声明需要注入的对象,由容器自动完成依赖对象的创建与注入
        public B(A a)
        {
            _a = a;
        }
    }     internal class Program
    {
        static void Main(string[] args)
        {
            // 将类型注册至容器中
            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<A>();
            // 设置对象的生命周期(单例模式)
            builder.RegisterType<B>().SingleInstance();             // 构造IoC容器
            IContainer container = builder.Build();
            // 从容器中获取对象
            B b = container.Resolve<B>();
        }
    }
}

5 结束语

依赖注入与控制反转的思想诞生于软件开发追求高内聚、低耦合的历史进程中,20世纪90年代末已在软件设计模式、单元测试中使用。2002年Java的Spring框架搭载IoC容器、AOP等大杀器风靡全球,DI与IoC被更多的开发者关注。直到最近的项目中涉及插件化框架,而IoC容器又是插件架构的最佳拍档,因此将其整理成文。如能给人予帮助,不甚荣幸。

<全文完>

依赖注入(DI)与控制反转(IoC)的更多相关文章

  1. 依赖注入(DI)和控制反转(IOC)

    依赖注入(DI)和控制反转(IOC) 0X1 什么是依赖注入 依赖注入(Dependency Injection),是这样一个过程:某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只 ...

  2. PHP依赖注入(DI)和控制反转(IoC)详解

    这篇文章主要介绍了PHP依赖注入(DI)和控制反转(IoC)的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 首先依赖注入和控制反转说的是同一个东西,是一种设计模式,这种设计模式用来减少程 ...

  3. 依赖注入(DI)和控制反转(IOC)的理解,写的太好了。

    学习过spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,今天和大家 ...

  4. 【串线篇】依赖注入DI与控制反转IOC

    DI&IOC 在spring框架中DI与IOC说的其实是一回事 一句话:本来我接受各种参数来构造一个对象,现在只接受一个参数——已经实例化的对象. 也就是说我对对象的『依赖』是注入进来的,而和 ...

  5. 轻松理解 Java开发中的依赖注入(DI)和控制反转(IOC)

    前言 关于这个话题, 网上有很多文章,这里, 我希望通过最简单的话语与大家分享. 依赖注入和控制反转两个概念让很多初学这迷惑, 觉得玄之又玄,高深莫测. 这里想先说明两点: 依赖注入和控制反转不是高级 ...

  6. 话说 依赖注入(DI) or 控制反转(IoC)

    科普:首先依赖注入和控制反转说的是同一个东西,是一种设计模式,这种设计模式用来减少程序间的耦合,鄙人学习了一下,看TP官网还没有相关的文章,就写下这篇拙作介绍一下这种设计模式,希望能为TP社区贡献一些 ...

  7. ASP.NET MVC进阶之路:深入理解依赖注入(DI)和控制反转(IOC)

    0X1 什么是依赖注入 依赖注入(Dependency Injection),是这样一个过程:某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只定义一个注入点.在程序运行过程中,客户 ...

  8. PHP 依赖注入(DI) 和 控制反转(IoC)

    要想理解 PHP 依赖注入 和 控制反转 两个概念,就必须搞清楚如下的两个问题: DI —— Dependency Injection 依赖注入 IoC —— Inversion of Control ...

  9. 聊一聊PHP的依赖注入(DI) 和 控制反转(IoC)

    简介 IoC Inversion of Control 控制反转DI Dependency Injection 依赖注入 依赖注入和控制反转说的实际上是同一种东西,它们是一种设计模式,这种设计模式用来 ...

  10. 依赖注入(DI)与控制反转(IOC)

    DI(依赖注入,Dependency Injection),和所谓的IoC(控制反转,Inversion of Control )是一个意思. DI是一种通过接口实现松耦合的设计模式.初学者可能会好奇 ...

随机推荐

  1. Python的OCR工具pytesseract解决TesseractNotFoundError: tesseract is not installed or it's not in your PATH. See README file for more information环境变量问题

    pytesseract是基于Python的OCR工具, 底层使用的是Google的Tesseract-OCR 引擎,支持识别图片中的文字,支持jpeg, png, gif, bmp, tiff等图片格 ...

  2. Qt数据库应用14-超级自定义委托

    一.前言 在QTableView.QTreeView以及对于衍生的QTableWidget.QTreeWidget类中,需要用到自定义委托的情形很多,比如提供下拉框选择,进度条展示下载进度啥的,默认的 ...

  3. Qt编写安防视频监控系统54-轮询配置

    一.前言 视频监控系统中少不了用到视频轮询,按照设计的基本原则,先满足基本的用户需求,稳定跑起来,再去折腾更复杂的应用场景,于是本系统也做了个基本的视频轮询功能,可以设置轮询方案,给某个轮询方案设置轮 ...

  4. Qt音视频开发41-人脸识别嵌入式

    一.前言 大概几年前搞过一套嵌入式linux上的人脸识别程序,当然人脸识别的核心算法并不是自己开发的,关于人脸识别算法这一块,虽然有众多的开源库可以用,甚至还可以用opencv搞算法训练深度学习之类的 ...

  5. Qt编写地图综合应用20-多浏览器内核

    一.前言 本人写Qt程序这么多年,比较喜欢支持多个Qt版本,尤其是钟情于支持任意Qt版本+任意系统+任意编译器,这句话说起来简单其实实现起来就不容易了,首先你得有个很多版本的测试环境,起码十几个Qt环 ...

  6. Qt音视频开发30-Onvif事件订阅

    一.前言 能够接收摄像机的报警事件,比如几乎所有的摄像机后面会增加报警输入输出接口,如果用户外接了报警输入,则当触发报警以后,对应的事件也会通过onvif传出去,这样就相当于兼容了所有onvif摄像机 ...

  7. Web网页端IM产品RainbowChat-Web的v7.1版已发布

    一.关于RainbowChat-Web RainbowChat-Web是一套Web网页端IM系统,是RainbowChat的姊妹系统(RainbowChat是一套基于开源IM聊天框架 MobileIM ...

  8. GIS开发的基础优化策略

    GIS开发的基础优化策略 1. GIS开发 空间字段要建对,类型明确,坐标系明确. 空间索引要建立,提高查询效率. 使用空间字段要谨慎,不用的地方不要查. 地图显示尽量用切片,用WMTS. WMS能用 ...

  9. AutoGen入门-让两个AI自行聊天完成任务

    AutoGen介绍 AutoGen 是一个开源编程框架,用于构建 AI 代理并促进多个代理之间的合作以解决问题.AutoGen 旨在提供一个易于使用和灵活的框架,以加速代理型 AI 的开发和研究,就像 ...

  10. 如何在 ASP.NET Core 中实现速率限制?

    在 ASP.NET Core 中实现速率限制(Rate Limiting)中间件可以帮助你控制客户端对 API 的请求频率,防止滥用和过载.速率限制通常用于保护服务器资源,确保服务的稳定性和可用性. ...