我正在尝试正确使用Inversion of Control。我的应用程序工作正常。我使用Unity作为IoC容器。但是,当我选择使用哪个具体类时,我认为我出错了。
在这个例子中,我有一个从特定数据源获取数据的类。根据文件类型,我调用数据访问器类。
此服务类检查类型,执行切换,然后选择要使用的具体类。
然而,似乎我在这里打破了IoC原则,通过在课堂上'新'来实现。我不再注入此服务类,因为此时我还没有确定我正在使用哪种文件类型。所以我不得不评论“注射”,而不是硬编码。
这是代码提取。
public class DataService : IDataService
{
IFileReader _fileReader;
public DataService(IFileReader fileReader)
{
// _fileReader = fileReader;
}
/// <summary>
/// Returns reporting data based on a group of export files.
/// </summary>
/// <param name="files">A list of files to analyse</param>
/// <returns></returns>
private List<RawFileData> GetRawData(string[] files)
{
foreach (var file in files)
{
// validate files exists.
switch (GetFileType(Path.GetFileName(file)))
{
case "CSV":
{
fileIsOK = true;
_fileReader = new CSVileConnector();
break;
}
case "TXT":
{
fileIsOK = true;
_fileReader = new TXTFileConnector();
break;
}
default:
break;
}
if (fileIsOK)
{
var finedata = _fileReader.ReadData(file);
data.Add(new RawFileData
{
DataItems = finedata,
FileName = file
});
}
}
return data;
}
这是处理此类情况的正确方法吗?在课堂创作方面,我不确定哪个子课程要“依赖”?然后在逻辑中决定它,并新建正确的Concrete类?
答案 0 :(得分:1)
一种改进可能是将读者的选择与阅读本身分开 - 一种称为IFileReader _getDataReader(string filename)
的私有方法。所以在你的foreach循环中你会说var reader = _getDataReader(filename);
。读者没有充分的理由成为你班级的私有财产,因为它没有被构建,可以不断变化,其使用范围仅限于GetRawData
。您可以考虑通过构造函数注入的内容是其接口定义中具有GetDataReader(string)
的类。这本身可以拥有一个私有Dictionary<string, Type>
,它将其文件扩展名作为其密钥,然后将该文件的读者作为值。如果你想要的话,你甚至可以在你的app.config中配置它。这就是所谓的Service Locator模式。
由于各种原因,this is actually an anti-pattern有很好的论点。也可能有人认为你已经过度思考了 - 因为你只有两种选择并且很容易以这种方式阅读 - 但将阅读器的选择与阅读本身分开至少会让你处于一个更容易理解的地方如果你需要改变。