2016-12-20 2 views
0

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

Теперь в моей реализации есть несколько различных текстовых обработчиков , каждый из которых способен обрабатывать свой собственный определенный набор строк. Есть два известных метода в каждом процессоре:

bool CanProcess(string text); 

и

string Process(string text); 

В действительности они могут быть помечены как статического но ради реализации общего интерфейса я не установив их в качестве статичный.

В дополнение к этим TextProcessors есть статический TextProcessorFinder класса. Как следует из названия, он находит лучший TextProcessor и обрабатывает входные данные.

public static class TextProcessorFinder 
{ 
    private static List<ITextProcessor> _processors; 

    static TextProcessorFinder() 
    { 
     _processors = Assembly.GetExecutingAssembly().GetTypes() 
      .Where(t => t.GetInterfaces().Contains(typeof(ITextProcessor)) 
      && t.IsClass && !t.IsAbstract) 
      .Select(t => (ITextProcessor)Activator.CreateInstance(t)) 
      .Where(t => t.IsActive) 
      .ToList(); 
    } 

    public static ITextProcessor GetTextProcessor(string text) 
    { 
     return _processors.Where(p => p.CanProcess(text)) 
      .OrderByDescending(p => p.Priority) 
      .FirstOrDefault(); 
    } 
} 

Что я ненавижу этот подход заключается в том, что я должен создать экземпляр каждого известного TextProcessor просто назвать их CanProcess функции.

Я попытался создать атрибут с простым Func подражать CanProcess функции:

[AttributeUsage(AttributeTargets.Class)] 
public class TextProcessorAttribute : Attribute 
{ 
    private Func<string, bool> func; 

    public TextProcessorAttribute(Func<string, bool> func) 
    { 
     this.func = func; 
    } 
} 

public interface ITextProcessor 
{ 
    bool IsActive { get; } 

    int Priority { get; } 

    bool CanProcess(string text); 

    string Process(string text); 
} 

// Hard-coded to true 
[TextProcessor((s) => { return true; })] 
public class SampleTextProcessor : ITextProcessor 
{ 
    // Implement ITextProcessor 
} 

К сожалению, однако, Func не является допустимым типом параметра атрибута.

Каков наилучший способ сделать это?

ответ

3

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

+0

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

+0

@ ZuiqPazu: Вам не нужно заставлять вас съеживаться, это прекрасно. –

0

С помощью метода CanProcess вы запрашиваете каждый полученный ITextProcessor, если он может обрабатывать текст. На мой взгляд, это нормально. Возможно, есть какая-то специализация в реализации ITextProcessor, в этом случае вы можете создавать более конкретные интерфейсы, ITextTypeAProcessor, ITextTypeBProcessor и т. Д. Затем вы можете фильтровать по интерфейсу в вашем методе GetTextProcessor.

+0

Я вижу, где вы собираетесь с этим. Однако на данный момент у меня нет каких-либо дополнительных особенностей для фильтрации. –

Смежные вопросы