Model view controller 使用依赖项注入创建昂贵的对象

Model view controller 使用依赖项注入创建昂贵的对象,model-view-controller,dependency-injection,unit-of-work,Model View Controller,Dependency Injection,Unit Of Work,我是DI新手,我正在从事一个MVC项目,在这个项目中,控制器被注入了一个新的内存,这个UnitOfWork包含了我域中每个实体类型的存储库。作为一个向导,我最初的想法是 public IRepository<Employee> Employees { get { if (_employees == null) { _employees = new SqlRepository<Employee>(_context);

我是DI新手,我正在从事一个MVC项目,在这个项目中,控制器被注入了一个新的内存,这个UnitOfWork包含了我域中每个实体类型的存储库。作为一个向导,我最初的想法是

public IRepository<Employee> Employees {
    get {
        if (_employees == null) {
            _employees = new SqlRepository<Employee>(_context);
        }
        return _employees;
    }
}
公共电子招聘员工{
得到{
如果(_employees==null){
_employees=新的SqlRepository(_上下文);
}
返回(u)员工;;
}
}
但是,我认为最好插入存储库,例如:

public SqlUnitOfWork(IRepository<Employee> employees)
{
    this.Employees = employees;
}
公共SqlUnitOfWork(IRepository员工)
{
这个。雇员=雇员;
}

但是,如果创建SqlRepository非常昂贵怎么办。并非每个控制器操作都使用每个存储库。在我改为DI之前,每个存储库只有在被访问时才会被创建。但是,现在所有存储库都是使用UnitOfWork创建的。当我已经在SqlUnitOfWork中时,我试图确定是否值得注入SqlRepositories?或者,我应该遵循MSDN示例吗?

您担心注入昂贵的对象来创建对象是对的

依赖项注入依赖于能够廉价地创建和注入对象(其中一些对象可能永远不会被使用)。这就是为什么在构造函数中或在构建对象图时执行“实际工作”是个坏主意

这里的问题是,
IRepository
的创建成本很高。如果它在构造器中做“真正的工作”,你能在需要之前把工作移到后面吗?这有点像懒惰的评估。这解决了问题的根本原因

有时候,这是不可能的。有一些变通办法:

  • 注入将为您提供IRepository(工厂)实例的内容
  • 将IRepository接口实现为LazyRepository。LazyRepository有一个成员变量,用于创建真正昂贵的存储库。在每个方法中,检查此变量是否为null。如果是,则创建真正的存储库。然后,每个方法都将数据挖掘到真实的存储库

    • 您担心注入昂贵的对象来创建对象是对的

      依赖项注入依赖于能够廉价地创建和注入对象(其中一些对象可能永远不会被使用)。这就是为什么在构造函数中或在构建对象图时执行“实际工作”是个坏主意

      这里的问题是,
      IRepository
      的创建成本很高。如果它在构造器中做“真正的工作”,你能在需要之前把工作移到后面吗?这有点像懒惰的评估。这解决了问题的根本原因

      有时候,这是不可能的。有一些变通办法:

      • 注入将为您提供IRepository(工厂)实例的内容
      • 将IRepository接口实现为LazyRepository。LazyRepository有一个成员变量,用于创建真正昂贵的存储库。在每个方法中,检查此变量是否为null。如果是,则创建真正的存储库。然后,每个方法都将数据挖掘到真实的存储库
      我不是ASP.NETMVC用户,但这种方法背后的想法不会改变。所以,把这个和盐一起吃

      根据您的描述,您正在使用多个具有工作单元的存储库,您无法决定是注入它们还是在其中创建它们。最好的做法是:两者都不

      当您处理未知数量的相同类型的依赖项时,更明智的做法是注入工厂实例。然后,您的
      UnitOfWork
      实现可以从所述工厂请求服务

      在这种情况下,工厂将检查此类服务是否已初始化。如果这样的服务已经初始化,您可以直接返回它。如果没有,则初始化该服务,缓存它(很可能在工厂中的某个类似数组的结构中),然后返回该实例


      一些其他注释

      • 存储库和工作单元都不应向控制器公开。它们是负责处理存储的结构。最终将模型层的内部细节公开给表示层。基本上,您的抽象正在泄漏

      • 我会小心阅读那个教程。这篇文章的作者似乎没有完全掌握DI的概念。如果您查看这段代码:

        public class SqlUnitOfWork : IUnitOfWork {
            public SqlUnitOfWork() {
                var connectionString =
                    ConfigurationManager
                        .ConnectionStrings[ConnectionStringName]
                        .ConnectionString;
                _context = new ObjectContext(connectionString);
            }
        
            /* --- SNIP --- */
        
            readonly ObjectContext _context;
            const string ConnectionStringName = "EmployeeDataModelContainer";
        }
        
        您可以看到,DB连接是在构造函数中基于常量初始化的,该常量已在
        SqlUnitOfWork
        类的定义中硬连线。这是一种非常糟糕的做法

      • 如果您想了解更多关于OOP实践的依赖注入的一般知识,我建议您阅读同一系列的文章和讲座

      我不是ASP.NETMVC用户,但这种方法背后的想法不会改变。所以,把这个和盐一起吃

      根据您的描述,您正在使用多个具有工作单元的存储库,您无法决定是注入它们还是在其中创建它们。最好的做法是:两者都不

      当您处理未知数量的相同类型的依赖项时,更明智的做法是注入工厂实例。然后,您的
      UnitOfWork
      实现可以从所述工厂请求服务

      在这种情况下,工厂将检查此类服务是否已初始化。如果这样的服务已经初始化,您可以直接返回它。如果没有,则初始化该服务,缓存它(很可能在工厂中的某个类似数组的结构中),然后返回该实例


      一些其他注释

      • 存储库和工作单元都不应向控制器公开。它们是负责处理存储的结构。最终将模型层的内部细节公开给表示层。基本上,您的抽象正在泄漏

      • 我会小心阅读那个教程