依赖容器:如何实例化对象实例

问题描述:

我使用Unity作为依赖注入引擎。它包含'repository'和'manager'类的接口/类。这些存储库负责从/到DB中获取/保存/更新数据,管理员知道与其他组件/类的对象关系。依赖容器:如何实例化对象实例

有工厂实现来获取依赖容器的实例(每个请求有1个实例)。当任何存储库/管理器类被实例化时,它接收依赖性容器作为构造器参数,并且可以在需要时创建所有其他管理器/存储库。

有2种方式来创建业务实体:

  1. 当数据从DB仓库中取出,创建对象的实例,并适当DB数据初始化它们,等之间的“容器”字段被初始化。
  2. 当在代码中创建对象以将其放入DB中时,它接受“IUnityContainer”参数。

因此,在这两种情况下,任何业务对象都有依赖容器,如果他需要获取任何数据,他可以获得适当的管理器实例并请求所需的数据。

问题描述:上周我看了一些问题/上,这样的状态是这样的答案:

  1. 对象实例不应该访问的依赖容器;
  2. 相反,他们应该在构造函数中接收所有必需的接口。

猜测,这同样适用于管理器/存储库类:我不应该将容器实例传递给它们的构造函数,而应该将接口放到其他所需的组件中。

对我来说,这似乎是合理的,但:

  • 我需要为任何目的是提供他所需要的所有接口(通常,每个经理/库/实体需要他们的3-5);

  • 有很多情况下,只需要1-2接口(所以我不想创造很多其他);

问题1:真的是很好的办法来 “隐藏” 的容器?为什么? (其实,我觉得我知道为什么,但如果你有好的答案,请告知)。

问题2:解决此类问题的最佳做法是什么? (我使用Linq2Sql,并考虑切换到EF)我不能通过DependencyContainer创建对象,我自己应该这样做(因为对象是通过使用在SQL站点上执行的表达式创建,将使用分配给公共属性的以下数据调用无参数构造函数;并且SQL方面不存在依赖项容器)。有没有解决方法?

我实现的技术细节:

经理基类构造函数的例子:库基类的

public abstract class ManagerBase : IManager 
{ 
    protected ManagerBase(IUnityContainer container) 
    { 
     DependancyContainer = container; 
    } 

    protected readonly IUnityContainer DependancyContainer; 

    ... 
} 

例子:

public abstract class RepositoryBase<T, TDb> : IRepository<T> 
    where T : IEntity 
    where TDb : class, IDbEntity, new() 
{ 
    protected abstract ITable<TDb> GetTable(); 

    public IQueryable<T> GetAll() 
    { 
     return GetTable().Select(GetConverter()); 
    } 

的数据是如何从数据库中提取实例:存储库创建对象的实例并使用适当的DB数据初始化它们,其中“容器”字段已初始化:

public class CountryRepository 
    : RepositoryBase<ICountry, DbData.Country>, ICountryRepository 
{ 
    protected override Expression<Func<DbData.Country, ICountry>> GetConverter() 
    { 
     return dbEntity => new Country 
     { 
      DependancyContainer = DependancyContainer, 

      Code = dbEntity.CountryCode, 
      Name = dbEntity.CountryName, 
     }; 
    } 

以下是调用时需要的数据是从数据库得到:

public class CountryManager : ManagerBase 
{ 
    ICountry GetCountryById(int countryId) 
    { 
     ICountryRepository repository = DependancyContainer.Resolve<ICountryRepository>(); 
     return repository.GetAll() 
      .Where(country=>country.Id==countryId) 
      .SingleOrDefault() 
      ; 
    } 
} 
+0

我想回答你的问题,但不清楚'*有很多情况下只需要1-2个接口(所以我不想创建很多其他);“ ...创建很多其他特别的东西? – 2011-03-17 21:33:56

+0

另外我认为你的示例'CountryManager'应该扩展'ManagerBase'? – 2011-03-17 21:52:56

+0

CountryManager是从managerBase继承的,这是正确的 – Budda 2011-03-19 14:47:25

Q1:其他人可能不同意,但一般情况下不应到你的域模型/实体提供您的DI容器类。我看到有两个主要原因:

  1. 将容器赋给实体类会混淆实体类的依赖关系。如果您依赖构造函数注入,您可以通过查看构造函数来查看它的依赖关系。如果你依赖属性注入,你可以通过查看属性来了解它的依赖关系,虽然这不如构造器注入清楚(即一些属性是实体类的数据,但其中一些属性是其他的接口为实体类提供服务;在分离两类时存在一些认知负担)。如果您将容器提供给实体,那么依赖关系将散布在整个课程中。
  2. 更简单的测试。如果您将容器传递给实体类,那么为了测试它,您将不得不模拟/存根容器以及它从容器中检索的接口。您始终可以设置一个轻量级容器,但这不仅仅是直接提供模拟/存根接口,还有更多的工作。

Q2:有人会说,好的做法(DDD在哪里存储库模式/强域模型模式来源于)不暴露你的实体类接口摆在首位。相反,他们应该包含可以实现的任何业务逻辑而不依赖于其他接口,并且更复杂的逻辑应该在Service类中(按照DDD的说法)。

Q3:你没有说你正在使用哪种对象关系映射工具,但可能通过某种拦截器/面向方面的编程模式来控制实体对象实例化过程。然后,这会使您的代码库更接近依靠这个特定的O/R映射器及其功能(即,尽管我在构建架构时通常倾向于避免担心这种情况,但难以从其轨道上改变它)。关于你的示例代码

一些更多的意见,可能会或可能不表示你的代码的其余部分:

  • 你看AutoMapper?您可能会发现,您在CountryRepository.GetConverter()课程中正在执行的手动映射更好。
  • 看起来您正在为DbData名称空间中的每个类建立并行实体类,大概是因为您无法将要在DbData命名空间类中插入的服务。也许我对Q2的回答会引导您朝着更好的方向发展(如果可能,请依靠服务并扩展DbData课程)。
  • 我不确定Manager正在播放什么角色......理想情况下,您的所有查询方法应该在存储库上,以便他们实际上可以对数据库执行SELECT ... FROM Country where Id = ?查询,而不是返回整个表并执行查询在内存中通过LINQ,毕竟这是数据库擅长的! (尽管针对您的应用程序的性能特征进行了有意的缓存优化)。 GetCountryById方法应该在CountryRepository本身我相信。

希望有帮助!

+0

存储库任务是提供映射。也许你是对的,我最好将诸如“GetCountryById”之类的函数从管理者移动到存储库。但是,我的经理人的目标是返回一个完整的对象。如果我将返回“订单”实体,它将不会一致,没有所有的订单记录...所以“订单管理器”将做2件事:从订单本身(从订单仓库)获取DB数据并从数据库订单获取 - 记录(来自OrderRecordRespotitory)。 OrderRepository只执行顺序对象映射。 – Budda 2011-03-19 14:43:43

+0

作为数据映射器我使用Linq2Sql。顺便说一句,谢谢,如果我的意见有价值,等待其他想法 – Budda 2011-03-19 14:50:15

+0

也许你应该更多地了解域驱动设计,有一个概念calles有界的上下文和聚合根。并非您域中的每个类都应该有自己的存储库(恕我直言),而是确定聚合根(您称为FULL对象)在您的域中并仅为它们提供存储库。这样的存储库将负责持久和检索构成根本根的所有模型。 – 2015-11-13 21:43:35