创建没有switch-case的类

时间:2016-09-08 00:27:50

标签: c# dependency-injection factory

我一直致力于从各种文件中读取数据并将其存储到公共数据库表中的程序。文件中的数据格式因数据源而异,使每个文件都是唯一的。我需要一种方法来根据数据源的名称来确定文件阅读器,并且我在避免使用switch-case语句时遇到了麻烦,即使有一个抽象工厂也是如此。我知道我可以注入IFileReader,但只能将交换机案例推到一个级别。

以下是我当前实施的一个示例。如何完全消除switch-case语句并仍然动态确定文件读取器?

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>();
    }
}

1 个答案:

答案 0 :(得分:0)

您可以通过创建一个抽象的FileProcessorBase类,然后创建从中继承的类来消除示例中的switch语句,每个类型的fileReader都有一个(见下文)。

这将从这个类中删除switch语句,但是你仍然需要一个switch语句来确定你需要哪个FileProcessorBase实例。我没有看到完全消除switch语句或条件逻辑的可能性,但如果你继续遵循这个过程,它最终会被推回到组成你的应用程序的组合根。

某些DI容器支持基于约定的注册,您可以使用它来完全消除switch语句,尽管仍然存在条件逻辑。

public abstract class FileProcessorBase
{
    protected  IFileReaderFactory _fileReaderFactory;
    protected  FooDbContext _fooDb;

    public void ProcessFile(string source, string filePath)
    {
        _fooDb.Foos.AddRange(GetFileReader().ReadFile(filePath));
        _fooDb.SaveChanges();
    }

    protected abstract IFileReader GetFileReader();
}

public class FileProcessorA : FileProcessorBase
{
    public FileProcessorA(IFileReaderFactory fileReaderFactory, FooDbContext fooDb)
    {
        _fileReaderFactory = fileReaderFactory;
        _fooDb = fooDb;
    }

    protected override IFileReader GetFileReader()
    {
        return _fileReaderFactory.CreateReader<FileReaderA>();
    }
}

public class FileProcessorB : FileProcessorBase
{
    public FileProcessorB(IFileReaderFactory fileReaderFactory, FooDbContext fooDb)
    {
        _fileReaderFactory = fileReaderFactory;
        _fooDb = fooDb;
    }

    protected override IFileReader GetFileReader()
    {
        return _fileReaderFactory.CreateReader<FileReaderB>();
    }
}