.net 依赖反转原则 VS 依赖注入

作者:微信公众号:【架构师老卢】
2-4 8:37
19

概述:在面向对象编程领域,依赖关系反转 (DI) 和依赖关系注入 (DI) 原则在实现可维护、可扩展和松散耦合的代码方面起着关键作用。在 C# 中,这些原则是编写可靠且可测试的应用程序的基础。让我们深入研究这些概念,了解它们的重要性,并探索 C# 中的实际示例。依赖关系反转原则 (DIP)依赖反转是 **Robert C. Martin(Uncle Bob)**提出的一个原则,作为 SOLID 原则的一部分。它表明高级模块不应依赖于低级模块;两者都应该依赖于抽象。抽象不应依赖于细节;细节应该取决于抽象。简单来说,这个原则强调:**对具体实现的抽象:**它促进定义接口或抽象类,以将高级模块与低级实现细

在面向对象编程领域,依赖关系反转 (DI) 和依赖关系注入 (DI) 原则在实现可维护、可扩展和松散耦合的代码方面起着关键作用。在 C# 中,这些原则是编写可靠且可测试的应用程序的基础。让我们深入研究这些概念,了解它们的重要性,并探索 C# 中的实际示例。

依赖关系反转原则 (DIP)

依赖反转是 **Robert C. Martin(Uncle Bob)**提出的一个原则,作为 SOLID 原则的一部分。它表明高级模块不应依赖于低级模块;两者都应该依赖于抽象。抽象不应依赖于细节;细节应该取决于抽象。

简单来说,这个原则强调:

  • **对具体实现的抽象:**它促进定义接口或抽象类,以将高级模块与低级实现细节分离。
  • **反转依赖关系的方向:**它们不是直接依赖于其他具体类的类,而是依赖于接口或抽象。

考虑一个类直接依赖于类的场景:BusinessLogicDataAccess

public class BusinessLogic  
{  
    private readonly DataAccess _dataAccess;  
  
    public BusinessLogic()  
    {  
        _dataAccess = new DataAccess();  
    }  
  
    // Methods using \_dataAccess  
}

这种紧密耦合使类依赖于类,因此很难替换或测试 .BusinessLogicDataAccessDataAccess

通过遵循依赖反转原则,我们可以重构以下代码:

public interface IDataAccess  
{  
    // Method signatures  
}  
  
public class DataAccess : IDataAccess  
{  
    // Implement methods  
}  
  
public class BusinessLogic  
{  
    private readonly IDataAccess _dataAccess;  
  
    public BusinessLogic(IDataAccess dataAccess)  
    {  
        _dataAccess = dataAccess;  
    }  
  
    // Methods using \_dataAccess  
}

现在,依赖于接口而不是特定的实现()。这种抽象提供了灵活性,支持注入不同的实现,便于测试,并在数据访问策略之间切换。BusinessLogicIDataAccessDataAccessIDataAccess

依赖注入 (DI)

依赖注入是一种实现依赖反转原则的设计模式。这是一种技术,其中对象从外部源接收其依赖项,而不是在内部创建它们。可以通过构造函数、属性或方法提供此外部源。

在 C# 中,可以通过多种方式实现依赖注入:

  1. 构造函数注入
  2. 属性注入
  3. 方法注入

让我们检查每种类型的简单示例。

构造函数注入

让我们看一下构造函数注入的简单代码示例:

public class BusinessLogic  
{  
    private readonly IDataAccess _dataAccess;  
  
    public BusinessLogic(IDataAccess dataAccess)  
    {  
        _dataAccess = dataAccess;  
    }  
  
    // Methods using _dataAccess  
}

在这里,依赖项 () 是通过构造函数注入的。IDataAccess

属性注入

让我们看一下属性注入的简单代码示例:

public class BusinessLogic  
{  
    public IDataAccess DataAccess { get; set; }  
  
    // Other methods using DataAccess  
}

在这种情况下,依赖项是通过公共属性注入的,这可能会导致可选依赖项。

方法注入

让我们看一下方法注入的简单代码示例:

public class BusinessLogic  
{  
    public void PerformOperation(IDataAccess dataAccess)  
    {  
        // Use dataAccess for operation  
    }  
}

依赖项作为方法的参数提供,适用于短期依赖项或一次性操作。

ASP.NET Core 中的依赖注入

像 ASP.NET Core 这样的框架提供了对依赖注入的内置支持,允许您通过构造函数注入自动注册服务并注入依赖关系。

您可以像下面的代码一样在 program.cs 中注册您的服务**。** 大多数情况下,我们在 program.cs 中注册 DI 服务。

var builder = WebApplication.CreateBuilder(args);  
  
builder.Services.AddTransient<IDataAccess, DataAccess>();  
// Other service registrations

在这里,我们使用 DI 的瞬态生存期注册了服务。之后,您可以通过构造函数注入来注入您的服务。

public class BusinessLogic  
{  
    private readonly IDataAccess _dataAccess;  
  
    public BusinessLogic(IDataAccess dataAccess)  
    {  
        _dataAccess = dataAccess;  
    }  
  
    // Methods using _dataAccess  
}

framework(ASP.NET Core) 在创建类实例时解析并注入指定的依赖项。

了解 ASP.NET Core 中的依赖项生存期

在 C# 中的依赖项注入 (DI) 的上下文中,DI 容器管理的依赖项的生存期或范围通常是指特定依赖项的实例保持活动状态的时间。通常使用三种常见的生存期或作用域:

  1. 态:瞬态生存期意味着每次请求依赖项或将其注入使用类时,都会创建一个新的依赖项实例。此范围适用于在多个请求中不保存状态的无状态服务或组件。在瞬态生存期中,会在该特定依赖项的每个请求上创建一个新实例。
builder.Services.AddTransient<IDataAccess, DataAccess>();

2. 单例:单例生存期是指容器在应用程序的整个生命周期内维护依赖项的单个实例。每当请求依赖项时,都会重用此实例,从而确保应用程序的所有部分共享同一实例。

builder.Services.AddSingleton<IDataAccess, DataAccess>();

3. 作用域:作用域生存期意味着每个作用域或每个请求创建一次依赖项的单个实例。对于 Web 应用程序,此范围通常与 HTTP 请求保持一致。在同一个 HTTP 请求中,会重用相同的实例,但后续请求会接收自己的实例。

builder.Services.AddScoped<IDataAccess, DataAccess>();

这些不同的生存期迎合了应用程序开发中的各种方案。开发人员应根据其应用程序中组件所需的特定要求和行为来选择适当的生存期。了解这些生存期有助于有效地管理内存,并确保依赖项在整个生命周期中的预期行为。

依赖注入的好处

  1. 解耦:DI 通过将依赖项的创建与依赖类分离来促进松散耦合,从而增强灵活性和可维护性。
  2. 可测试性:通过注入依赖关系,在单元测试期间可以更轻松地模拟或替换依赖关系,从而可以对单个组件进行隔离且高效的测试。
  3. 可扩展性和可重用性:DI 通过允许注入不同的实现来促进组件的重用,从而促进应用程序架构的可扩展性和适应性。

结论

依赖关系反转和依赖关系注入是现代软件开发中的关键概念,尤其是在 C# 和其他面向对象的语言中。这些原则通过解耦依赖关系和实现组件实现的灵活性来促进代码的可维护、可测试和可伸缩。

通过采用这些原则,开发人员可以创建模块化、可重用且易于维护的软件系统。Mastering Dependency Injection 使开发人员能够编写更简洁、更易于维护的代码库,这些代码库更易于扩展和测试,最终导致更强大、更灵活的应用程序。

相关留言评论
昵称:
邮箱:
阅读排行