我有一个验证代码的规范。它看起来如下:
public ClassificationSpecification : ISpecification<Classification> {
HashSet<string> codes;
// constructor elided
public IsSatisfiedBy(Classification classification) {
return codes.Contains(classification.Code);
}
}
有效代码来自数据库中的Classification
表。我的问题是,哪个是更好的依赖注入构造函数?
public CodeSpecification(IEnumerable<string> codes) {
this.codes = new HashSet<string>(codes);
}
或
public CodeSpecification(IRepository<Classification> repository) {
this.codes = new HashSet<string>(repository.Select(x => x.Code));
}
所有重要的问题:为什么?
答案 0 :(得分:1)
我会使用这个构造函数:
private readonly IRepository<Classification> _repository;
public CodeSpecification(IRepository<Classification> repository)
{
_repository = repository;
}
然后,在实际调用您的类时找到有效代码:
public bool IsSatisfiedBy(Classification classification)
{
var _repository.Any(x => x.Code == classification.Code);
}
这确保在需要之前不会完成任何实际工作,将应用程序的初始化与运行时分开。它还确保您始终使用IsSatisfiedBy
中的新数据;缓存构造函数中的值会引入一段时间,存储库中的代码可能会发生变化。
如果代码数量很大,并且存储库不能有效地执行Any
,您可能仍希望实现缓存。在第一次调用IsSatisfiedBy
:
private readonly HashSet<string> _codes;
private readonly object _codesSync = new object();
public bool IsSatisfiedBy(Classification classification)
{
if(_codes == null)
{
lock(_codesSync)
{
if(_codes == null)
{
_codes = new HashSet<string>(_repository.Select(x => x.Code));
}
}
}
return _codes.Contains(classification.Code);
}
依赖注入对象中的构造函数是基础结构元素;通常应推迟任何类型的域逻辑,直到另一个域调用该对象。
答案 1 :(得分:1)
你的第二个构造函数是真正的工作(通过存储库),这是一个坏主意。见http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/
您需要确定加载所有值(传递构造函数所需的值)是否有效,或者您希望在每次调用时查找它们(在构造函数中传入存储库并存储它)。