【设计模式】依赖注入(Dependency Injection, DI)

依赖注入(Dependency Injection, DI)是一种软件设计模式,用于实现对象之间的松耦合,同时提升代码的可测试性和可维护性。它主要用于管理和提供对象的依赖关系,而不需要在代码中手动创建依赖实例。

核心概念

  • 依赖 :一个类需要的服务或对象。例如,类 A 需要类 B 提供某些功能,那么 B 就是 A 的依赖。
  • 注入:将依赖通过外部方式传递给类,而不是让类直接创建或获取这些依赖。

在传统编程中,如果类 A 需要使用类 B,通常会在 A 中直接创建一个 B 的实例。这种方式称为"紧耦合",会导致以下问题:

  1. 难以测试 :无法轻松替换 B 的实现进行单元测试。
  2. 难以扩展 :修改 B 的实现可能需要更改 A 的代码。
  3. 依赖管理困难:多个类之间的依赖关系可能变得复杂且难以维护。

依赖注入通过将依赖的创建工作交给外部框架或容器解决了这些问题。


实现依赖注入的方法

  1. 构造函数注入(Constructor Injection) 在构造函数中通过参数传递依赖对象。

    复制代码
    public class A
    {
        private readonly B _b;
    
        public A(B b)
        {
            _b = b;
        }
    
        public void DoSomething()
        {
            _b.SomeMethod();
        }
    }
  2. 属性注入(Property Injection) 通过公共属性设置依赖。

    复制代码
    public class A
    {
        public B B { get; set; }
    
        public void DoSomething()
        {
            B?.SomeMethod();
        }
    }
  3. 方法注入(Method Injection) 通过方法参数传递依赖。

    复制代码
    public class A
    {
        public void DoSomething(B b)
        {
            b.SomeMethod();
        }
    }

DI 容器的作用

在 C# 中,依赖注入通常结合 DI 容器使用 ,比如 Microsoft 提供的 ASP.NET Core 自带 DI 容器 或第三方库(如 Autofac、Ninject)。DI 容器的主要功能是:

  1. 管理依赖关系。
  2. 自动创建对象并注入其依赖。
  3. 提供对象的生命周期管理(例如单例、瞬态、作用域)。

以下是 ASP.NET Core 的 DI 示例:

复制代码
// 服务接口
public interface IService
{
    void Serve();
}

// 服务实现
public class Service : IService
{
    public void Serve()
    {
        Console.WriteLine("Service Called");
    }
}

// 使用服务的控制器
public class Controller
{
    private readonly IService _service;

    public Controller(IService service)
    {
        _service = service;
    }

    public void Action()
    {
        _service.Serve();
    }
}

// 程序入口
class Program
{
    static void Main(string[] args)
    {
        // 创建 DI 容器
        var serviceProvider = new ServiceCollection()
            .AddTransient<IService, Service>() // 注册服务
            .BuildServiceProvider();

        // 从容器中获取控制器
        var controller = new Controller(serviceProvider.GetService<IService>());

        controller.Action();
    }
}

优点

  1. 松耦合:对象不直接依赖具体实现,而是依赖于接口或抽象。
  2. 更易测试:通过注入模拟对象(Mocks),轻松进行单元测试。
  3. 可维护性和扩展性更好:更容易修改或扩展应用程序。

适用场景

  • 复杂应用程序:需要管理大量依赖关系时。
  • 单元测试驱动开发(TDD):依赖注入便于注入 mock 对象。
  • 分层架构或微服务:减少模块间的耦合。

通过依赖注入,可以有效改善代码的结构和质量,使开发过程更高效、灵活。

相关推荐
勘察加熊人17 分钟前
wpf+c#路径迷宫鼠标绘制
开发语言·c#·wpf
小黄人软件1 小时前
C# ini文件全自动界面配置:打开界面时读ini配置到界面各控件,界面上的控件根据ini文件内容自动生成,点保存时把界面各控件的值写到ini里。
开发语言·c#
二进制人工智能2 小时前
【QT5 网络编程示例】TCP 通信
网络·c++·qt·tcp/ip
莫有杯子的龙潭峡谷4 小时前
3.31 代码随想录第三十一天打卡
c++·算法
AaronZZH5 小时前
【进阶】vscode 中使用 cmake 编译调试 C++ 工程
c++·ide·vscode
杨筱毅5 小时前
【性能优化点滴】odygrd/quill 中将 MacroMetadata 变量声明为 constexpr
c++·性能优化
NaZiMeKiY6 小时前
C++ 结构体与函数
开发语言·c++
涛ing6 小时前
【Git “fetch“ 命令详解】
linux·c语言·c++·人工智能·git·vscode·svn
学习是种信仰啊6 小时前
QT图片轮播器实现方法二(QT实操2)
开发语言·c++·qt
gc_22997 小时前
C#测试Excel开源组件ExcelDataReader
c#·excel·exceldatareader