我使用 Unity 作为依赖注入(inject)引擎。它包含用于“存储库”和“管理器”类型的类的接口(interface)/类。这些存储库负责从/向数据库获取/保存/更新数据,并且管理人员“知道”与其他组件/类的对象关系。
实现了工厂来获取依赖容器的实例(每个请求 1 个实例)。当任何存储库/管理器类被实例化时,它接收依赖容器作为构造函数参数,并且可以在需要时创建所有其他管理器/存储库。
有两种方法可以创建业务实体:
因此,在这两种情况下,任何业务对象内部都有依赖容器,如果他需要获取任何数据,他可以获取适当管理器的实例并请求所需的数据。
问题陈述:上周我阅读了一些关于 SO 的问题/答案,这些问题/答案是这样的:
猜猜,这同样适用于管理器/存储库类:我不应该将容器实例传递给它们的构造函数,而是应该将接口(interface)放置到其他必需的组件中。
对我来说,这似乎很合理,但是:
问题 1 :“隐藏”容器真的是好方法吗?为什么? (实际上,我觉得我知道为什么,但如果你有好的答案,请指教)。
问题 2 :解决此类问题的最佳做法是什么?
问题 3 :在我从 DB 中提取对象的特定实现中(我使用 Linq2Sql,并考虑切换到 EF)我无法通过 DependencyContainer 创建对象,我应该自己做(因为对象是通过使用表达式创建的)在 SQL 站点上执行时,将使用分配给公共(public)属性的以下数据调用无参数构造函数;并且依赖容器在 SQL 端不可用)。有什么解决方法吗?
我的实现的技术细节:
Manager 基类构造函数示例:
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());
}
如何从数据库中提取数据的示例:存储库创建对象实例并使用适当的数据库数据对其进行初始化,其中“容器”字段已初始化:
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()
;
}
}
最佳答案
Q1: 其他人可能不同意,但通常您不应该将 DI 容器提供给域模型/实体类。我认为有两个主要原因:
Q2 :有人会说好的做法(在 DDD 下,存储库模式/强域模型模式来自于此)首先不会将您的实体类暴露给接口(interface)。相反,它们应该包含可以在不依赖其他接口(interface)的情况下实现的任何业务逻辑,并且更复杂的逻辑应该在 Service 类中(用 DDD 的说法)。
Q3 :您没有说明您使用的是哪种对象关系映射工具,但可以通过某种拦截器/面向方面的编程模式对实体对象实例化过程进行一些控制。然而,这确实使您的代码库更接近于依赖于这个特定的 O/R 映射器及其功能(即更难在轨道上改变它,尽管我通常倾向于在做出架构选择时避免担心这一点)。
关于您的示例代码的更多观察结果可能会或可能不会指示您的代码库的其余部分:
CountryRepository.GetConverter()
类中所做的手动映射的更好替代方法。 DbData
命名空间中的每个类构建并行实体类,大概是因为您无法将想要的服务插入到 DbData
命名空间类中。也许我对 Q2 的回答会指引你走向更好的方向(如果可能的话,依靠服务并扩展 DbData
类)。 Manager
正在扮演什么角色...理想情况下,您所有的查询方法都应该在存储库中,以便它们实际上可以对数据库执行 SELECT ... FROM Country where Id = ?
查询,而不是返回整个表并在内存中执行查询通过 LINQ,毕竟这是数据库所擅长的! (尽管针对您的应用程序的性能特征进行了有意的缓存优化)。我相信 GetCountryById
方法应该在 CountryRepository
本身上。 希望有帮助!
关于c# - 依赖容器 : how to instantiate object instances,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5342927/