2016-09-08 2 views
1

저는 다양한 파일의 데이터를 읽고 공통 데이터베이스 테이블에 저장하는 프로그램을 작성했습니다. 파일의 데이터 형식은 데이터 원본에 따라 달라 지므로 각 파일이 고유합니다. 데이터 소스의 이름을 기반으로 파일 판독기를 결정할 방법이 필요하며 추상적 인 공장을 갖추고 있어도 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>(); 
    } 
} 
+0

이것은 반사를 사용하여 달성 할 수 있습니다. http://stackoverflow.com/questions/232535/how-do-i-use-reflection-to-call-a-generic-method – jrobichaud

+0

상태 패턴을 살펴볼 수 있습니다. http://www.codeproject.com/Articles/489136/UnderstandingplusandplusplusStateplusP를 구현합니다. 개인적으로 나는 대개 케이스 진술로 돌아가고있다. – Sam

+0

여기에는 너무 많은 옵션이 있습니다. 당신은 약간의 연구를하고 질문을 좁힐 필요가 있습니다. 스택 오버플로는 이미 일부 입력 매개 변수 (예 : 대리자 사전)를 기반으로하는 일련의 작업에서 선택하거나 동적 매개 변수화 된 유형의 제네릭 메소드를 호출하는 광범위한 작업 (많은 옵션 중 두 가지만 포함)에 대한 질문과 대답으로 가득차 있습니다 이 경우 귀하에게 제공됩니다. –

답변

0

당신은 추상 FileProcessorBase 클래스를 생성 한 다음 상속 클래스, 파일 리더의 종류마다 1 개의 (아래 참조)를 작성하여 예에서 스위치 문을 제거 할 수 있습니다.

이렇게하면이 클래스에서 switch 문을 제거하지만 필요한 경우 FileProcessorBase의 인스턴스를 결정하기 위해 switch 문이 필요합니다. 나는 switch 문이나 조건부 로직을 완전히 없앨 수는 없지만,이 프로세스를 계속 수행하면 결국 애플리케이션을 작성하는 composition root로 되돌아 간다.

일부 DI 컨테이너는 컨벤션 기반 등록을 지원하므로 조건문 논리가 있지만 스위치 문을 완전히 제거 할 수 있습니다.

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