2010-12-14 2 views
2

Как я могу сделать дизайн этого класса более динамичным, чтобы я мог добавлять новые расширения и типы по мере необходимости.Как создать метод, содержащий множество операторов IF или Switch

public class Processor 
{ 
    public Processor(string fileName) 
    { 
     string extension = Path.GetExtension(fileName); 
     if(extension == "jpg" || extension == "gif" || extension == "png") 
     { 
      //Process Image file type 
     } 
     else if(extension == "xls" || extension == "xlsx") 
     { 
      //Process spreadsheet type 
     } 
     else if(extension == "doc" || extension == "docx") 
     { 
      //Process document file type 
     }  
     //and so forth ... 
    } 
} 

Нам может понадобиться обработать .tiff файлы в будущем, или мы, возможно, придется обрабатывать видео файлы, а это означает новый, если филиал

else if(extension == "avi" || extension == "mp4") 
{ 
    //Process video file type 
} 

Как вы можете видеть, это может быть очень долго.

Допустимые типы файлов и группы хранятся в БД ...

Можно ли рекомендовать какие-либо образцы или умные идеи, чтобы решить эту проблему? Приветствия

ответ

3

Я рекомендовал бы придумать интерфейс для ваших различных процессоров файлов для реализации:

public interface IFileProcessor 
{ 
    void Process(string fileName); 
    IEnumerable<string> FileExtensions {get;} 
} 

Затем использовать завод, чтобы получить соответствующий процессор для конкретного файла имя. Как и другие ответчики, я рекомендую вам использовать словарь для хранения сопоставлений процессоров и их имен файлов. В этом примере используется отражение для регистрации каждого файлового процессора, который он находит в загруженных сборках. Это хорошо подходит для вашего требования к расширению, поскольку все, что вам нужно, это для какой-то загруженной сборки иметь класс, который реализует этот интерфейс, и он будет автоматически зарегистрирован на заводе-изготовителе. Тем не менее, вы можете придумать любую систему, вы хотите для регистрации этих типов:

public class ProcessorFactory 
{ 
    static IDictionary<string, IFileProcessor> ProcessorsByExtension = 
     new Dictionary<string, IFileProcessor>(); 

    static ProcessorFactory() 
    { 
     var processorTypes = 
      from a in AppDomain.CurrentDomain.GetAssemblies() 
      from t in a.GetTypes() 
      where typeof(IFileProcessor).IsAssignableFrom(t) 
      select t; 
     foreach(var t in processorTypes) 
     { 
      // Preferably use your DI framework to generate this. 
      var processor = (IFileProcessor)Activator.CreateInstance(t); 
      foreach(var ext in processor.FileExtensions) 
      { 
       if(ProcessorsByExtension.ContainsKey(ext)) 
       { 
        throw new InvalidOperationException(
         "Multiple processors are registered to extension " + ext); 
       } 
       ProcessorsByExtension[ext] = processor; 
      } 
     } 
    } 

    public IFileProcessor GetProcessorForFile(string fileName) 
    { 
     string extension = Path.GetExtension(fileName); 
     return ProcessorsByExtension[extension]; 
    } 
} 

Типичная реализация интерфейса процессора файл может выглядеть следующим образом:

public class ImageFileProcessor : IFileProcessor 
{ 
    public IEnumerable<string> FileExtensions 
    { 
     get {return new[]{"jpg", "gif", "png"};} 
    } 
    public void Process(string fileName) 
    { 
     // Process Image file type 
    } 
} 

Этот подход сохраняет ваш код более модульным и расширяемый, обеспечивая отличную производительность, даже если у вас есть огромный список файловых процессоров.

0

для этого конкретного случая я бы построить что-то вроде

List<string> excelExtensions = new List<string>(){ "xls", "xlsx" }; 
List<string> wordExtensions = new List<string>(){ "doc", "docx" }; 

if(excelExtensions.Contains(extension)) 
{ 
} 

if(wordExtensions.Contains(extension)) 
{ 
} 

и т.д.?

+0

HashSet может быть быстрее. –

+0

Этот подход по-прежнему не затрагивает проблему очень долгого метода или проблемы обслуживания, при которой новый элемент if {} должен добавляться каждый раз при добавлении совершенно нового типа файла. – JeffH

4

Используйте словарь.

Dictionary<string, IFileHandler> fileHandlers = new Dictionary<string, IFileHandler> 
{ 
    { "jpg", imageHander }, 
    { "gif", imageHander }, 
    { "xls", spreadsheetHander }, 
    // ... 
}; 

Затем использовать его следующим образом:

public void Process(string fileName) 
{ 
    string extension = Path.GetExtension(fileName); 

    // TODO: What should happen if the filetype is unknown? 
    fileHandlers[extension].Process(fileName); 
} 

Допустимые типы и группы файлов хранятся в БД ...

Тогда вы, вероятно, хотите запросите базу данных, чтобы получить правильную группу из расширения и использовать группу в качестве словарного ключа, а не расширения.

1

Одним из способов может быть сбор таблицы (списка), где каждый элемент содержит расширение вместе с информацией о том, что делать с именами с этим расширением.

Затем вы можете написать простой цикл, который сравнивается с каждым расширением в таблице.

Если то, что вы делаете с каждым расширением, является сложным и не может быть определено в простой таблице, то вместо этого вы можете включить делегат. Когда цикл находит соответствующее расширение, он может вызвать соответствующего делегата для обработки имени.

3

Эта структура, как правило, является плохим, если ожидается, что она будет расширена по причинам, о которых вы заявляете (прежде всего, чтобы вернуться и добавить ветви кода).

Я бы реализовал это как словарь, привязанный к строкам расширения файла и содержащий делегаты метода в качестве значений. Это было бы, если было бы правильно спроектировано, позволить вам добавлять новые расширения, не затрагивая старый код, поскольку новый код будет иметь совершенно другой метод, который может даже существовать вне класса, который имеет эту логику. Затем просто найдите подходящего делегата для вызова с помощью расширения файла.

Простой пример:

//Put this in your class somewhere 
public readonly Dictionary<string, Action<FileInfo>> fileHandlers = new Dictionary<string, Action<FileInfo>>(); 

... 

//depending on the dictionary's visibility, you can add these from pretty much anywhere 
fileHandlers.Add("xls", ProcessExcelFile); 
fileHandlers.Add("xlsx", ProcessExcelFile); 
fileHandlers.Add("jpg", ProcessImageFile); 

... 

//Then all you have to do to invoke the logic is... 
fileHandlers[extension](fileInfo); 
1

Существует правило для этого refactoring--

  • Заменить состояние с полиморфизмом/стратегии. Очевидная проблема с if/switch, скорее всего, будет иметь ошибки в таком коде, и ее трудно поддерживать или улучшать.

Учитывая то же самое и «Принцип открытого закрывания» (- Классы должны быть открыты для расширения, но закрыты для модификаций.).

Я предлагаю для кода ниже.

public class Processor 
    { 
     private Dictionary<string,FileParserBase> _fileExtension2FileParser; 

     public Processor() { 
      _fileExtension2FileParser = new Dictionary<string, FileParserBase>(); 

      AddParser(new DocExtensionWordParser()); 
      AddParser(new DocXExtensionWordParser()); 
      //..more,more 
     } 

     private void AddParser(FileParserBase fileParserBase) { 

      _fileExtension2FileParser.Add(fileParserBase.Extension, fileParserBase); 
     } 


    public void Process(string fileName) 
    { 
     string extension = Path.GetExtension(fileName); 
     FileParserBase fileParser; 
     if (_fileExtension2FileParser.TryGetValue(extension, out fileParser)) { 
      fileParser.Process(fileName); 
     } 

    } 
    } 

    public interface FileParserBase 
    { 
     string Extension { get; } 
     void Process(string filePath); 
    } 

    public abstract class WordParserBase : FileParserBase 
    { 
     private string _extension; 

     public WordParserBase(string extension) 
     { 
      _extension = extension; 
     } 

     public override void Process(string filePath) 
     { 
      //Do the processing for WORD Document 
     } 

     public override string Extension 
     { 
      get { return _extension; } 
     } 
    } 

    public class DocExtensionWordParser : WordParserBase 
    { 

     public DocExtensionWordParser():base("doc"){} 
    } 

    public class DocXExtensionWordParser : WordParserBase 
    { 

     public DocXExtensionWordParser() : base("docx") { } 
    } 
Смежные вопросы