Alva

Alva

programmer
github
telegram
email

dotnetの依存性注入-01.紹介

本文示例代码,均采用 .NET 6,具体的代码可以在这个仓库 Articles.DI 中获取。

让我们看这么一段简单的代码:

// https://github.com/alva-lin/Articles.DI/tree/master/WorkerService1
public class MessageWriter {
	public void Write(string message) => Console.WriteLine(message);
}

public class Worker : BackgroundService {
	private readonly MessageWriter _msgWriter = new MessageWriter();

	protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
		while (!stoppingToken.IsCancellationRequested) {
			_msgWriter.Write($"Worker running at: {DateTime.Now}");
			await Task.Delay(1000, stoppingToken);
		}
	}
}

在上面的代码中,Worker类包含有一个MessageWriter类的实例成员,这个类创建并直接依赖于MessageWriter类。这样的代码有一些问题:

  • 如果_msgWriter变量要替换成别种类型的实现,需要修改Worker类;
  • 如果MessageWriter类具有其他依赖项,则必须在Worker类中进行配置;
  • 难以对Worker类进行单元测试。

如果有一个统一的管理者,负责MessageWriter类型的实例化,然后将其传递给有需求的类,就能做到这两个类之间的依赖解除,减少了硬编码。而这,就是依赖注入。

依赖注入和控制反转#

依赖注入(英文 Dependency Injection,简称 DI),是一种在类及其依赖项之间实现控制反转(英文 Inversion of Control,简称 IoC)的技术。

控制反转,是面向对象编程中的一种设计原则,可以用来减少程序代码间的耦合程度。除了依赖注入外,还有一种实现控制反转的方法,叫做 “依赖查找”。

大多数程序都由多个类相互引用,彼此依赖合作以实现业务逻辑,这使得每个对象都需要获取其他服务的引用。如果这个获取过程需要靠对象自己实现,那么这将导致类之间高度耦合,难以维护和调试。

传统应用中,如果 A 服务要获取 B 服务,则需要在自己的代码块中实例化。而如果使用依赖注入,A 服务只需声明所需的服务,由外部容器来负责生成实例,A 服务只需接收即可。整个过程从主动变成了被动,反转了对象的获取过程,即实现了控制反转

下面两张图展示了两种依赖项关系图:

直接依赖项关系图

直接依赖项关系:类 A 调用类 B 的方法,类 B 调用类 C 的方法,则在编译时,类 A 依赖与类 B,类 B 依赖与类 C。

反转依赖项关系图

应用依赖反转后,类 A 引用的是接口 IB 的方法,不再直接依赖于类 B。在编译时,则是类 A 和类 B 引用了接口 IB,和前面的直接依赖相比,反转了依赖项。而类 B 和类 C 之间也是相似的。

IoC 解耦过程

这张图,生动形象的解释了控制反转是如何解耦服务之间的依赖。

参考链接#

依赖注入 - 维基百科

控制反转 - 维基百科

依赖关系反转 - 现代 ASP.NET Web 应用程序电子书

.NET 中的依赖关系注入

Inversion of Control Containers and the Dependency Injection pattern

依赖注入和控制反转的理解

控制反转(IoC)与依赖注入(DI)

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。