【设计模式】依赖注入(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 对象。
  • 分层架构或微服务:减少模块间的耦合。

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

相关推荐
Laurence1 小时前
C++ 引入第三方库(一):直接引入源文件
开发语言·c++·第三方库·添加·添加库·添加包·源文件
蒸汽求职2 小时前
机器人软件工程(Robotics SDE):特斯拉Optimus落地引发的嵌入式C++与感知算法人才抢夺战
大数据·c++·算法·职场和发展·机器人·求职招聘·ai-native
charlee442 小时前
最小二乘问题详解17:SFM仿真数据生成
c++·计算机视觉·sfm·数字摄影测量·无人机航测
Tanecious.3 小时前
蓝桥杯备赛:Day4-P9749 公路
c++·蓝桥杯
旖-旎3 小时前
分治(库存管理|||)(4)
c++·算法·leetcode·排序算法·快速选择算法
Tanecious.3 小时前
蓝桥杯备赛:Day3-P1102 A-B 数对
c++·蓝桥杯
Rsun045514 小时前
设计模式应该怎么学
java·开发语言·设计模式
Tanecious.4 小时前
蓝桥杯备赛:Day3-P1918 保龄球
c++·蓝桥杯
良木生香4 小时前
【C++初阶】:C++类和对象(下):构造函数promax & 类型转换 & static & 友元 & 内部类 & 匿名对象 & 超级优化
c语言·开发语言·c++
三雷科技5 小时前
使用 `dlopen` 动态加载 `.so` 文件
开发语言·c++·算法