I have been working on a program that reads data from various files and stores it into a common database table. The format of data in the files varies based on the data source, making each file unique. I need a way to determine the file reader based on the name of the data source, and I am having trouble avoiding a switch-case statement, even with an abstract factory in place. I know I could inject the IFileReader
but that only pushes the switch-case up a level.
Below is an example of my current implementation. How can I completely eliminate the switch-case statement and still dynamically determine the file reader?
public class FileProcessor
{
private readonly IFileReaderFactory _fileReaderFactory;
private readonly FooDbContext _fooDb;
public FileProcessor(IFileReaderFactory fileReaderFactory, FooDbContext fooDb)
{
_fileReaderFactory = fileReaderFactory;
_fooDb = fooDb;
}
public void ProcessFile(string source, string filePath)
{
IFileReader fileReader;
switch (source)
{
case "A":
fileReader = _fileReaderFactory.CreateReader<FileReaderA>();
break;
case "B":
fileReader = _fileReaderFactory.CreateReader<FileReaderB>();
break;
default:
throw new Exception($"Unknown source: {source}");
}
_fooDb.Foos.AddRange(fileReader.ReadFile(filePath));
_fooDb.SaveChanges();
}
}
public interface IFileReaderFactory
{
IFileReader CreateReader<T>() where T : IFileReader, new();
}
public class FileReaderFactory : IFileReaderFactory
{
public IFileReader CreateReader<T>() where T : IFileReader, new()
{
return new T();
}
}
public interface IFileReader
{
List<Foo> ReadFile(string filePath);
}
public class FileReaderA : IFileReader
{
public List<Foo> ReadFile(string filePath)
{
// read file a
return new List<Foo>();
}
}
public class FileReaderB : IFileReader
{
public List<Foo> ReadFile(string filePath)
{
// read file b
return new List<Foo>();
}
}