Альтернатива наследованию для анализаторов сообщений - PullRequest
0 голосов
/ 11 октября 2019

Я работаю над анализатором протокола 9p. Протокол имеет кучу сообщений. Я хочу иметь простой интерфейс типа auto message = parser.pares(bytesStream); Какого типа message, если я хочу, чтобы мой протокол был расширяемым?

В настоящее время я использую variant<Protocol messages>. В простом случае - где я знаю все возможные версии - это просто. Но я бы хотел поддерживать разные версии протокола (расширения: 9p2000.e, 9p2000.u, 9p2000.l и т. Д.), И каждая из них может добавлять дополнительные типы сообщений. Протокол имеет фиксированный размер заголовка Length-Type-Value вида. Так что я всегда знаю тип сообщения с учетом заголовка. Но в зависимости от согласованной версии протокола - тип сообщений означает немного другое.

Каковы альтернативы использованию наследования при реализации анализаторов расширяемого протокола?

То есть янужна функция формы:

parser.parse(header, byteStream) -> Message;

Проблема здесь в том, что тип сообщения зависит от версии. Обычно это можно решить с помощью наследования типов:

struct IMessage {}; 
struct p2000::Open : public IMessage {...};
struct p2000e::Open : public IMessage {...};
struct p2000l::Open : public IMessage {...};

И parse () -> unique_ptr;// или что-то в этом роде

Проблема в том, что я хотел бы избежать выделения памяти. Таким образом, хотелось бы не использовать make_unique (...);

Текущая реализация просто возвращает:

parse(...) -> variant<p2000::Open, p2000e::Open, p2000l::Open, ...>;

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

selectParser(version: String) -> versionedParser;

Без сохранения строки current_version способ реализовать - это сохранить переходtable: messgetype -> *parserFunc;Это таблица указателей на функцию парсера сообщений. Только выдача каждой функции, возвращаемый тип должен быть одинаковым. Что означает, что я не могу реализовать их независимо от другой версии. То есть: parse_p92000l_open() должен быть «осведомлен» о типах сообщений p92000e, потому что тип возвращаемого варианта должен будет перечислять все возможные типы сообщений. Который пропускает знания о сообщениях из независимой версии протокола.

Так что, в сущности, я хочу найти лучший способ выразить: Наследование - это базовый класс зла понятия.

Кто-нибудь решал эту проблему раньше?

1 Ответ

0 голосов
/ 11 октября 2019

Я хочу иметь простой интерфейс, такой как

auto message = parser.parse(bytesStream);

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

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

...