为什么我应该在构造函数中使用接口类型的对象而不是实际类对象

时间:2015-01-29 09:02:41

标签: c# asp.net-mvc entity-framework

我已将我的企业级项目外包给自由职业者,我也得到了很好的设置。但是现在合同已经完成,而且这个人也转向了新技术,换言之,不愿意延长合同。 现在我正在研究这个代码。我在C#和MVC方面有2年的背景经验。下面是我的应用程序架构的粗略概念。希望我尽力抽象出企业级应用程序的架构细节。如果您需要进一步了解任何问题,请与我们联系。


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

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类。这是一个实现此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接口的类具有以下结构:

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 Pattern扮演:

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

现在,实现此接口的Repository类如下所示:

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用于控制器以访问Data对象。 换句话说,为国家控制器实现构造函数注入时,为什么我们依赖于接口而不是实际的类对象?

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

3)在Controller的构造函数中我使用了Lazy&gt;,那么这个懒惰的目的是什么呢?它实际上是否有益如果是,那么以什么方式?

1 个答案:

答案 0 :(得分:3)

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

EfRepository类要求使用其构造函数注入其依赖项 - 这称为 构造函数注入 。我们还可以允许通过公共属性注入依赖项, 称为 setter injection

  

MVC模式最重要的特征之一是它能够实现   关注点分离。我们想要应用程序中的组件   尽可能独立,并尽可能减少相互依赖   我们可以管理。

     

在我们理想的情况下,每个组件都不了解任何其他组件   组件,只处理应用程序的其他区域   抽象接口。这被称为松散耦合,它会产生   更轻松地测试和修改我们的应用接口帮助我们   解耦组件。

     

我们需要的是获取实现给定对象的方法   接口,而无需直接创建实现对象。   该问题的解决方案称为依赖注入(DI),   也称为控制反转(IoC)。

     

DI是一种设计模式,它完成了我们开始的松散耦合   添加界面。

报价是从this本书的第3章复制的。