разработка бизнес-парсера MSG / переписывание с нуля - PullRequest
1 голос
/ 25 октября 2008

Я забочусь о критических приложениях в моем проекте. Он делает вещи, связанные с анализом бизнес-сообщений (унаследованный стандарт), их обработкой и последующим сохранением некоторых результатов в БД (другие приложения выбирают это). После более чем года моей работы (у меня есть и другие приложения, за которыми нужно присматривать) приложение наконец-то стало стабильным. Я ввел строгую политику TDD, и у меня 20% покрытия модульными тестами (спасибо Michael Feathers за вашу книгу!), Большинство из которых в критических частях. У меня также есть несколько фитнес-тестов в «белой коробке» (там рассматриваются все бизнес-сценарии). Я чувствую, что не могу в дальнейшем рефакторинг этого приложения, и я могу спокойно играть с ним. Он разработан так плохо, я хочу переписать его. Само приложение содержит около 20 тысяч сложных устаревших кодов C / C ++. Были и другие зависимости, но мне удалось отделить большинство из них.


Все, что у меня есть, это компилятор Sun C ++, cppunitlite, STLPort и Boost. Пожалуйста, не предлагайте другие технологии (без XML, Java и т. Д.), Так как это не вариант в моей организации. Я хотел бы сделать это с современным C ++ (возможно, поиграть с метапрограммированием ...), TDD от начала до конца.

Есть около 30 типов сообщений, которые мне нужно проанализировать. Каждая из них состоит из 3-10 строк, большинство из них довольно похожи. Это корень зла -> много дублирования кода. У каждого сообщения есть класс, описывающий, как он должен быть проанализирован. Взгляните на главное дерево наследования:

                             MSG_A                     MSG_B
                            /     \                   /     \
                    MSG_A_NEW   MSG_A_CNL      MSG_B_NEW   MSG_B_CNL

Оба дерева уходят намного глубже. Между MSG_A_NEW и MSG_B_NEW есть очень небольшие различия. Он должен обрабатываться одним классом, который может быть внедрен с небольшой настройкой.

Мой первоначальный план - иметь один общий класс сообщений, который будет настроен. Некоторая сущность (строитель ...?) Взглянет на сообщения и инициализирует соответствующий объект, который сможет проанализировать сообщение. Другая сущность сможет узнать, что это за линия, и эта информация будет использоваться строителем. Я планирую написать несколько парсеров, которые отвечают за разбор только одной конкретной строки. Это позволит мне повторно использовать его при разборе различных сообщений.

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

имеет минимальное и максимальное число, если строки - имеет некоторые обязательные строки - имеет несколько дополнительных строк - определенные строки должны быть в определенных местах (то есть дата не может быть перед типом сообщения), порядок имеет значение

Мне нужно проверить формат сообщений.


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

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

Ответы [ 4 ]

1 голос
/ 28 октября 2008

Я бы посоветовал вам , а не наследовать ваши конкретные классы обработки сообщений от базовых классов, которые содержат общий код, подобный этому:


      CommonHandler
            ^                                   ^
            |                                   |  = inheritance
       MsgAHandler
        ^       ^
        |       |
ANewHandler     ACnlHandler

Этот подход страдает от плохого повторного использования: например, если вы хотите обработать какое-то сообщение, которое должно что-то делать из A_NEW и A_CNL, у вас довольно быстро закончится множественное наследование.

Вместо этого я бы выбрал класс, содержащий общий код, который выполняет вызовы интерфейса для настройки этого общего кода. Примерно так:

<code></p>

<p>BasicHandler <>--- IMsgHandler    ------------\
             1  1  ^  ^   ^  ^    *           |            ^
                   |  |   |  |                |            |   = inheritance
         MsgAHandler  |   |  ANewHandler    1 |
             ACnlHandler  HandlerContainer <>-/           <>-  = containment</p>

<p>

Класс HandlerContainer можно использовать для группировки поведения других обработчиков.

Этот паттерн называется «Составной», если я не ошибаюсь. И для создания правильных экземпляров обработчиков вам, конечно, понадобится какая-то фабрика.

Удачи!

0 голосов
/ 27 октября 2008

Я бы посоветовал взглянуть на библиотеки, предоставляемые boost, например, Tuple или mpl::vector. Эти библиотеки позволяют создавать список несвязанных типов, а затем оперировать ими. Очень грубая идея состоит в том, что у вас есть последовательности типов для каждого типа сообщений:

Seq1 -> MSG_A_NEW, MSG_A_CNL
Seq2 -> MSG_B_NEW, MSG_B_CNL

Как только вы узнаете тип сообщения, вы используете соответствующий кортеж с шаблоном функции, который применяет первый тип кортежа к данным. Затем следующая запись в кортеже и т. Д.

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

0 голосов
/ 26 октября 2008

То, что действительно звучит как забавный вызов. : -)

Ваш «первоначальный план» звучит как хороший: вычеркните всю подобную обработку между всеми сообщениями и поместите код для них в базовый класс сообщений. Изменяющиеся элементы могут стать виртуальными функциями (например, CheckForRequiredLines или VerifyLineOrder), возможно, с реализациями по умолчанию для наиболее распространенного случая. Затем выведите другие классы для определенных типов сообщений.

Трудно дать общий совет для такой проблемы проектирования, как эта. Мне кажется, что ваша основная функция синтаксического анализатора соответствует шаблону Factory Method, но это единственная, которую я могу легко идентифицировать. (Я не слишком знаком с именами шаблонов проектирования - я использую многие из них, но я только узнал, что они имеют имен пару лет назад.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...