2014-01-16 2 views
1

Итак, как я понимаю, шаблон контекста является анти-шаблоном. Однако я столкнулся с проблемой, которую мне нужно решить, что, вероятно, оправдывает ее использование.Является ли это допустимым аргументом для шаблона Context?

У меня есть набор классов, которые реализуются с IParser. Интерфейс IParser требует, чтобы разработчики могли реализовать CanRead(Stream) - где разработчик возвращает, выводит ли он поток в соответствующем формате для чтения. Так, например, CsvParser будет читать поток и проверять, удовлетворяет ли оно регулярному выражению ([\w]*),.

Далее они должны реализовать Parse(Stream), в котором разработчики возьмут Stream и проанализируют его по-своему, пока они возвращают перечислимые POCO из их проанализированных данных.

Теперь, пожалуйста, это руб. Существует несколько парсеров, таких как XmlParser, CsvParser и т. Д. Каждый Parser знает, как разбирать собственный формат, но данные поступают от сторонних пользователей. Мы не можем гарантировать, что макет их данных соответствует тому, что ожидает каждый из парсеров. То есть, хотя они могут очень хорошо находиться в действительных Xml или Csv, у них могут не быть одинаковые имена полей для сопоставления данных (один источник может иметь <DateTime>...</DateTime>, другой может иметь <Time>...</Time>) и т. Д.

Я не хочу обязательно приходится писать парсеры для каждого клиента, у которого могут быть небольшие вариации. Чтобы устранить эту проблему, я предлагаю, чтобы у меня был класс, который будет служить «картой». Это будет иметь свойства, которые будут называться ожидаемым именем поля и иметь значение реального имени/местоположения поля (в терминах файлов Csv это будет столбец). Это будет передано в метод Parse(Stream).

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

EDIT: В истинном тест управляемой моды развития, я придумал решение, которое выглядит следующим образом:

  • IParser «s метод синтаксического анализа теперь Parse(Stream stream, string dateReference, string valueReference, string idReference).
  • Создайте новый интерфейс под названием IFieldLocator<T> со способом GetField(String fieldReference, T input).

Теперь для реализации:

  • CsvFile является значение объекта, который принимает строку Csv в это конструктор и позволяет получить к нему доступ через GetField(int lineNumber, int columnNumber).
  • CsvFieldLocator инвентарь IFieldLocator<CsvFile> и это метод GetField(string fieldReference, CsvFile input) - это обертывание для доступа к CsvFile.GetField(int lineNumber, int columnNumber). Строка в fieldReference является ссылкой на столбцы/строки в excel.
  • CsvParser занимает IFieldLocator<CsvFile> в своем конструкторе.

Вот как я решил эту проблему. Тем не менее, меня все еще интересует ваше мнение.

ответ

0

Подтвердив вашу проблему:

  1. У вас есть парсер CSV, который анализирует конкретный формат CSV и возвращает что-то полезное, и XML-парсер, который разбирает конкретный формат XML и возвращает что-то полезное.
  2. Вы получаете CSV и XML-потоки, содержащие эквивалентные данные, но в другом формате.
  3. У вас есть понимание различий в этих форматах (предположительно, в противном случае вы не сможете создать объект контекста, который вы предлагаете).

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

Я бы не стал менять парсер через проходящий контекст, я бы преодолел разрыв.

Есть два места, которые можно сделать.

Во-первых, поскольку хорошо разработанный синтаксический анализатор XML или CSV для конкретной цели будет построен поверх общего анализатора XML или CSV, мы можем поместить что-то посредине. Это легко с CSV (например, если общий анализатор дает перечисление string[] для каждой строки, мы можем перемещать поля вокруг и, возможно, переформатировать некоторые), но, как правило, сложнее с XML (вы могли бы, конечно, написать класс, полученный из XmlReader, который, например, скажем, местное имя Time, когда источник XmlReader читал из сказанного, что это было DateTime, но это противно).

Второе - это преобразование самого потока в соответствие с желаемым форматом. Это легко в XML (просто используйте XSLT, и для каждого источника нужен только другой XSLT-шаблон), а в CSV немного сложнее, хотя и далеко не от науки о ракетах.

Предлагаю этот второй подход.

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

Основываясь на этом, вы могли бы затем упростить ваш синтаксический анализ: почему у вас два парсера, если вы переформатируете потоки на лету? XSLT для создания CSV из заданного входного XML является тривиальным, и код для получения данного формата XML из CSV также прост. Настройтесь на один парсер, основываясь на том, как легко поддерживать код, и насколько часто этот конкретный формат входит в число потоков, с которыми вам приходится иметь дело, и добавлять фильтр или цепочку фильтров для устранения разрыва.

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

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