Model view controller 使用依赖项注入创建昂贵的对象
我是DI新手,我正在从事一个MVC项目,在这个项目中,控制器被注入了一个新的内存,这个UnitOfWork包含了我域中每个实体类型的存储库。作为一个向导,我最初的想法是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);
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。如果是,则创建真正的存储库。然后,每个方法都将数据挖掘到真实的存储库
UnitOfWork
实现可以从所述工厂请求服务
在这种情况下,工厂将检查此类服务是否已初始化。如果这样的服务已经初始化,您可以直接返回它。如果没有,则初始化该服务,缓存它(很可能在工厂中的某个类似数组的结构中),然后返回该实例
一些其他注释
- 存储库和工作单元都不应向控制器公开。它们是负责处理存储的结构。最终将模型层的内部细节公开给表示层。基本上,您的抽象正在泄漏
- 我会小心阅读那个教程。这篇文章的作者似乎没有完全掌握DI的概念。如果您查看这段代码:
您可以看到,DB连接是在构造函数中基于常量初始化的,该常量已在public class SqlUnitOfWork : IUnitOfWork { public SqlUnitOfWork() { var connectionString = ConfigurationManager .ConnectionStrings[ConnectionStringName] .ConnectionString; _context = new ObjectContext(connectionString); } /* --- SNIP --- */ readonly ObjectContext _context; const string ConnectionStringName = "EmployeeDataModelContainer"; }
类的定义中硬连线。这是一种非常糟糕的做法SqlUnitOfWork
- 如果您想了解更多关于OOP实践的依赖注入的一般知识,我建议您阅读同一系列的文章和讲座
UnitOfWork
实现可以从所述工厂请求服务
在这种情况下,工厂将检查此类服务是否已初始化。如果这样的服务已经初始化,您可以直接返回它。如果没有,则初始化该服务,缓存它(很可能在工厂中的某个类似数组的结构中),然后返回该实例
一些其他注释
- 存储库和工作单元都不应向控制器公开。它们是负责处理存储的结构。最终将模型层的内部细节公开给表示层。基本上,您的抽象正在泄漏
- 我会小心阅读那个教程