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

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

相关推荐
拾忆-eleven1 小时前
C++算法(19):整数类型极值,从INT_MIN原理到跨平台开发实战
数据结构·c++·算法
Hxyle1 小时前
c++设计模式
开发语言·c++·设计模式
摘星编程1 小时前
并发设计模式实战系列(17):信号量(Semaphore)
设计模式·并发编程
奥修的灵魂2 小时前
C#生成二维码和条形码
c#
琢磨先生David2 小时前
Java 企业级开发设计模式全解析
java·设计模式
神仙别闹2 小时前
基于QT(C++)实现(图形界面)校园导览系统
数据库·c++·qt
明月看潮生2 小时前
青少年编程与数学 02-018 C++数据结构与算法 25课题、图像处理算法
c++·图像处理·算法·青少年编程·编程与数学
我是一只鱼02233 小时前
LeetCode算法题 (反转链表)Day17!!!C/C++
数据结构·c++·算法·leetcode·链表
不当菜虚困3 小时前
JAVA设计模式——(十一)建造者模式(Builder Pattern)
java·设计模式·建造者模式
codefly-xtl3 小时前
责任链设计模式
java·开发语言·设计模式