C# 您在依赖项中寻找什么来确定它是否应该是注入依赖项?
我很难弄清楚何时应该注入依赖项。让我们仅使用我的项目中的一个简单示例:C# 您在依赖项中寻找什么来确定它是否应该是注入依赖项?,c#,.net,dependency-injection,C#,.net,Dependency Injection,我很难弄清楚何时应该注入依赖项。让我们仅使用我的项目中的一个简单示例: class CompanyDetailProvider : ICompanyDetailProvider { private readonly FilePathProvider provider; public CompanyDetailProvider(FilePathProvider provider) { this.provider = provider; } publ
class CompanyDetailProvider : ICompanyDetailProvider {
private readonly FilePathProvider provider;
public CompanyDetailProvider(FilePathProvider provider) {
this.provider = provider;
}
public IEnumerable<CompanyDetail> GetCompanyDetailsForDate(DateTime date) {
string path = this.provider.GetCompanyDetailFilePathForDate(date);
var factory = new DataReaderFactory();
Func<IDataReader> sourceProvider = () => factory.CreateReader(
DataFileType.FlatFile,
path
);
var hydrator = new Hydrator<CompanyDetail>(sourceProvider);
return hydrator;
}
}
class CompanyDetailProvider:ICompanyDetailProvider{
私有只读文件路径提供程序;
public CompanyDetailProvider(FilePathProvider提供程序){
this.provider=提供者;
}
public IEnumerable GetCompanyDetailsForDate(日期时间日期){
字符串路径=this.provider.GetCompanyDetailFilePathForDate(日期);
var factory=new DataReaderFactory();
Func sourceProvider=()=>factory.CreateReader(
DataFileType.FlatFile,
路径
);
var hydrator=新hydrator(sourceProvider);
返回水合器;
}
}
(不是生产质量!)
ICompanyDetailProvider
负责为消费者提供CompanyDetail
s的实例。具体实现CompanyDetailProvider
是通过使用Hydrator
从文件中水合CompanyDetail
的实例来实现的,Hydrator使用反射来填充来自IDataReader
的T
的实例。显然,CompanyDetailProvider
依赖于DataReaderFactory
(它返回给定文件路径的OleDbDataReader
实例)和DataReader
。应该注入这些依赖关系吗?插入文件路径提供程序
正确吗?我应该检查哪些品质来决定是否应该注射 如何确定类是否应该使用依赖项注入
这个类需要外部依赖项吗 如果是,注射 如果否,则没有依赖项 回答“注入FilePathProvider是否正确?”是的,它是正确的 编辑:为了澄清,任何外部依赖都是指调用不相关但依赖的类,特别是当它涉及物理资源(如从磁盘读取文件路径)时,但这也意味着任何类型的服务或模型类的逻辑与类的核心功能无关
一般来说,只要你打电话给新的接线员,就可以猜测到这一点。在大多数情况下,当新操作符必须处理除数据传输对象以外的任何类时,您都希望重构掉它的所有用法。当类位于使用位置的内部时,如果新语句降低了复杂性(如new DataReaderFactory()),则可以使用新语句然而,对于构造函数注入来说,这似乎也是一个非常好的选择。我倾向于更自由地注入依赖项,因此我肯定希望同时注入IDataReader以摆脱新的DataFactoryReader和Hyderator。它使所有东西都更加松散地耦合在一起,这当然使它更易于维护
另一个很容易马上实现的好处是更好的可测试性。您可以创建IDataReader和Hyderator的模拟,将单元测试隔离为GetCompanyDetailsForDate方法,而不必担心datareader和Hyderator内部会发生什么。我通过意图/机制镜头评估依赖项的使用点:这段代码是否清楚地传达了其意图,还是我必须从一堆实现细节中提取出来 如果代码看起来确实像一堆实现细节,我将确定输入和输出,并创建一个全新的依赖项来表示所有“如何”背后的原因。然后,我将复杂性推到新的依赖项中,使原始代码更简单、更清晰 当我阅读这个问题中的代码时,我清楚地看到了基于日期的文件路径检索,后面是一组不透明的语句,这些语句没有明确传达在特定路径上读取特定类型实体的目标。我可以努力克服它,但那会使我步履蹒跚 我建议您在获得路径后,提高计算后半部分的抽象级别。首先,我将定义一个实现代码输入/输出的依赖项:
public interface IEntityReader
{
IEnumerable<T> ReadEntities<T>(string path);
}
公共接口IEntityReader
{
IEnumerable可读实体(字符串路径);
}
然后,使用此接口重写原始类:
public sealed class CompanyDetailProvider : ICompanyDetailProvider
{
private readonly IFilePathProvider _filePathProvider;
private readonly IEntityReader _entityReader;
public CompanyDetailProvider(IFilePathProvider filePathProvider, IEntityReader entityReader)
{
_filePathProvider = filePathProvider;
_entityReader = entityReader;
}
public IEnumerable<CompanyDetail> GetCompanyDetailsForDate(DateTime date)
{
var path = _filePathProvider.GetCompanyDetailsFilePathForDate(date);
return _entityReader.ReadEntities<CompanyDetail>(path);
}
}
公共密封类CompanyDetailProvider:ICompanyDetailProvider
{
专用只读IFilePathProvider\u filePathProvider;
私有只读客户端Reader _entityReader;
public CompanyDetailProvider(IFilePathProvider filePathProvider、IEntityReader entityReader)
{
_filePathProvider=filePathProvider;
_entityReader=entityReader;
}
public IEnumerable GetCompanyDetailsForDate(日期时间日期)
{
var path=\u filePathProvider.GetCompanyDetailsFilePathForDate(日期);
返回_entityReader.ReadEntities(路径);
}
}
现在,您可以对血淋淋的细节进行沙箱处理,这些细节在隔离中变得非常紧密:
public sealed class EntityReader : IEntityReader
{
private readonly IDataReaderFactory _dataReaderFactory;
public EntityReader(IDataReaderFactory dataReaderFactory)
{
_dataReaderFactory = dataReaderFactory;
}
public IEnumerable<T> ReadEntities<T>(string path)
{
Func<IDataReader> sourceProvider =
() => _dataReaderFactory.CreateReader(DataFileType.FlatFile, path);
return new Hydrator<T>(sourceProvider);
}
}
公共密封类EntityReader:EntityReader
{
私有只读IDataReaderFactory\u dataReaderFactory;
公共实体读卡器(IDataReaderFactory dataReaderFactory)
{
_dataReaderFactory=dataReaderFactory;
}
公共IEnumerable可读实体(字符串路径)
{
函数源提供程序=
()=>_dataReaderFactory.CreateReader(DataFileType.FlatFile,路径);
返回新的查询器(sourceProvider);
}
}
如本例所示,我认为您应该将数据读取器工厂抽象出来,并直接实例化读取器。区别在于
EntityReader
使用数据读取器工厂,而它只创建数据读取器。它实际上根本不依赖于实例;相反,它是一个工厂。你说的“外部依赖”是什么意思?修饰语“external”对“dependency”有什么意义?对外部资源(如dat)的依赖性