Похоже, консенсус заключается в том, что сначала нужно разрешить анализатор и передать его в статический метод. Предполагая, что вы уже знаете T
, который вы анализируете, это кажется хорошим подходом. Это просто возлагает ответственность за получение экземпляра синтаксического анализатора на один уровень вверх до класса, который вызывает ParseInput
.
Полагаю, это означает, что у вас будет такой код:
var orderParser = new OrderParser();
var orders = InputParser.ParseInput(input, orderParser);
Опять же, это предполагает, что вы знаете T
, который вам нужен (Order
в данном случае). Если вы анализируете вещи в общем, вы не будете знать T
и, следовательно, не будете знать, что OrderParser
- это класс, который вы должны использовать. В этом случае вы сталкиваетесь с той же проблемой: вам все еще нужно использовать оператор switch или контейнер, чтобы абстрагировать различные реализации IParser<T>
.
Общий анализ
Если это ваша ситуация, вы можете объединить метод экземпляра с фабрикой синтаксического анализатора, чтобы избежать обращения к контейнеру напрямую из класса потребления:
public class InputParser
{
private readonly IParserFactory _parserFactory;
public InputParser(IParserFactory parserFactory)
{
_parserFactory = parserFactory;
}
public IEnumerable<T> ParseInput<T>(string input)
{
var xml = XElement.Parse(input);
// some more code here
var parser = _parserFactory.CreateParser<T>();
return parser.Parse(xml);
}
}
Реализация IParserFactory
может обрабатывать связь с контейнером:
public sealed class ResolvedParserFactory : IParserFactory
{
private readonly IContainer _container;
public ResolvedParserFactory(IContainer container)
{
_container = container;
}
public IParser<T> CreateParser<T>()
{
return _container.Resolve<IParser<T>>();
}
}
Некоторые контейнеры, такие как Autofac , могут сгенерировать эту фабрику для вас или предоставить другие способы отделить класс фабрики от прямой ссылки на контейнер .
Неуниверсальный синтаксический анализ
Если код, который вызывает ParseInput
, действительно знает, какой T
нужно проанализировать, например, с OrderParser
выше, вам не нужна сложность фабрики. В этом случае у меня есть несколько предложений по улучшению API.
ParseInput
- отличный кандидат на метод расширения в IParser<T>
. Вы также можете отделить синтаксический анализ XML от другого кода и T
синтаксический анализ:
public static IEnumerable<T> ParseInput(this IParser<T> parser, XElement input)
{
// some more code here
return parser.Parse(input);
}
public static IEnumerable<T> ParseInput(this IParser<T> parser, string input)
{
return parser.ParseInput(XElement.Parse(input));
}