Я пытаюсь найти хороший дизайн для того, над чем я работаю. В качестве примера рассмотрим класс 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 не является допустимым типом параметра атрибута.
Каков наилучший способ сделать это?
Я думаю, это работает. Они действительно дешевы, но что-то о создании кучи экземпляров для методов, которые могут быть статическими (за исключением реализации интерфейса), заставляет меня съеживаться. –
@ ZuiqPazu: Вам не нужно заставлять вас съеживаться, это прекрасно. –