为什么我应该在 Constructor 中使用 Interface 类型的对象而不是 Actual Class Object

Why should I use Interface type of object in Constructor instead of Actual Class Object

我已经将我的企业级项目外包给了一个自由职业者,我也得到了很好的设置。但是现在那个合同已经结束了,这个人也转向了一项新技术,也就是说不愿意续约。 现在我正在自己研究这段代码。我确实有 2 3 年的 C# 和 MVC 背景。以下是我的应用程序架构的粗略概念。希望我已经尽力抽象出企业级应用程序的架构细节。如果您需要进一步简要说明任何问题,请告诉我。


我所有的实体都定义为 C# POCO classes as:

public class Product : BaseEntity
{
   public int ProductId { get; set; }
   public string ProductName { get; set; }
}

现在我有一个像这样的 IDbContext :

public interface IDbContext : IDisposable
{
    IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity;      
}

基础实体是每个 POCO 实体继承的部分 POCO class。这是一个 class 将此 IDBContext 实现为:

public class MyObjectContext : DbContext, IDbContext
{
    public new IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity
    {
        return base.Set<TEntity>();
    }
}

现在我定义了一个 IDbContextFactory,它负责提供 DBContexts 作为:

public interface IDbContextFactory
{
    Lazy<IDbContext> CreateDbContext();
}

实现此 IDBContextFactory 接口的 class 具有以下结构:

public class MyDbContextFactory : IDbContextFactory
{
    public MyDbContextFactory(string dbConnectionString)
    {
        _dbConnectionString = Settings.DbConnectionString;
        _dbContext = CreateDbContext();
    }

    public IDbContext CreateDbContext()
    {
        IDbContext dbContext = new IDbContext(() => CreateNewContext());
        return dbContext;
    }

    private MyObjectContext CreateNewContext()
    {
        return new MyObjectContext (_dbConnectionString);
    }
}

这里 IRepo 模式的作用是:

public partial interface IRepository<T> where T : BaseEntity
{
    T GetById(object id);
}

现在实现此接口的存储库 class 如下所示:

public partial class EfRepository<T> : IRepository<T> where T : BaseEntity
{
    private readonly Lazy<IDbContext> _dbContext;
    private readonly IDbContextFactory _dbContextFactory;
    private readonly Lazy<ObjectStateManager> _objectStateManager;

    public EfRepository(IDbContextFactory dbContextFactory)
    {
        _dbContextFactory = dbContextFactory;
        _dbContext= _dbContextFactory.CreateDbContext();
        _objectStateManager= new Lazy<ObjectStateManager>(() => ((IObjectContextAdapter)_dbContext.Value).ObjectContext.ObjectStateManager);
    }

    public T GetById(object id)
    {
        return this.Entities.Find(id);
    }
}

到目前为止,我们已经完成了数据库访问管理的基础架构级别设置。现在的事情是将此设置用于控制器(因为我直接从控制器访问存储库)如下:

public class CountryController: BaseController
{
    private readonly Lazy<IRepository<Country>> _countryRepository;

    public CountryController(Lazy<IRepository<Country>> countryRepository)
    {
        _countryRepository = countryRepository;
    }

    public Country GetCountryById(int id)
    {
        Country country = _countryRepository.Value.GetById(id);

        if (country != null)
            return country;
        else
            return null;
    }

希望以上都清楚。下面是我需要回答的一些问题:

1) 为什么我们有这样的分层流程:

IDBContext -> IDBContextFactory -> IRepository <T>

然后最终将此 IRepository 用于控制器以访问数据对象。 换句话说,为什么我们在为 Country Controller 实现构造函数注入时依赖接口而不是实际的 Class 对象?

2) 这是企业级应用程序的正确方法吗,因为它应该具有很大的可扩展性以供将来使用。如果还有其他的,我会很高兴知道吗?

3) 在 Controller 的构造函数中,我使用了 Lazy>,那么这个 Lazy 的目的是什么?它实际上有益吗?如果是,那么以什么方式有益?

这是设计模式。它被称为依赖注入.

EfRepositoryclass 要求使用其构造函数注入其依赖项——这称为 构造函数注入.我们还可以允许通过 public 属性 注入依赖项, 被称为setter注入

One of most important features of the MVC pattern is that it enables separation of concerns. We want the components in our application to be as independent as possible and to have as few interdependencies as we can manage.

In our ideal situation, each component knows nothing about any other component and only deals with other areas of the application through abstract interfaces. This is known as loose coupling, and it makes testing and modifying our application easier. Interfaces help us decouple components.

What we need is a way to obtain objects that implement a given interface without having to create the implementing object directly. The solution to this problem is called dependency injection (DI), also known as Inversion of Control (IoC).

DI is a design pattern that completes the loose coupling we started by adding the interface.

引用自 this 书第 3 章。