2009-11-10 2 views
1

либо в качестве членов, независимо от того, может быть статическими, отдельными пространства имен, через друг-х, через перегрузки даже, или любую другую функцию языка C++ ...методы проектирования для нескольких целевых сериализации/форматов (не версии)

Когда облицовочного проблема поддержки нескольких/разных форматов, возможно, протоколов или любых других целей для ваших типов, что было самым гибким и удобным для обслуживания подходом?

Были ли какие-либо соглашения или четкие победители?

Краткое примечание, почему особый подход помог бы быть замечательным.

Спасибо.

[ProtoBufs как предложения не должны отрезать его для upvote, независимо от того, насколько гибким, что особенно осущ может быть :)]

ответ

2

Чтение уже опубликованных ответов, я могу согласиться только на подход среднего уровня.

В принципе, в исходной задаче у вас есть 2 различных иерархии:

  • п классы
  • м протоколов

Наивное использование Visitor рисунка (насколько мне это нравится) приведет только к n*m методам ... который действительно важен и является шлюзом к кошмару обслуживания. Полагаю, вы уже это заметили, иначе бы вы не спросили!

«Очевидным» целевым подходом является решение n+m, где две иерархии четко разделены. Это, конечно, представляет собой средний уровень.

Идея, таким образом, ObjectA -> MiddleTier -> Protocol1.

В принципе, это то, что делают протокольные буферы, хотя их проблема различна (от одного языка к другому с помощью протокола).

Это может быть довольно трудно выработать средний уровень:

  • вопросы производительности: фаза «перевод» добавить некоторые накладные расходы, и здесь вы идете от 1 до 2, это может быть смягчены, хотя, но вам придется работать над этим.
  • Проблемы с совместимостью: некоторые протоколы не поддерживают рекурсию, например (xml или json do, edifact does not), поэтому вам, возможно, придется согласиться на наименее общий подход или разработать способы эмуляции такого поведения.

Лично я хотел бы пойти на "переопределение" язык JSON (который является чрезвычайно простым) в C++ иерархия:

  • INT
  • строки
  • списки
  • словари

Применение шаблона Composite для их объединения.


Конечно, это только первый шаг. Теперь у вас есть фреймворк, но у вас нет ваших сообщений.

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

  • В-кода спецификации: ваше сообщение состоит из примитивов/другие сообщения
  • Использование сценария генерации кода: это кажется излишним, но ... ради завершение я думал, что я бы назвал это, как я не знаю, сколько сообщений вы действительно нужны :)

Переходим к реализации:

Herb Sutter и Андре сказал я Alexandrescu в их C++ Coding Standards

Предпочитают методы, не другу, не являющиеся членами

Это относится очень хорошо к MiddleTier -> Protocol шага> создает Protocol1 класс, а затем вы можете иметь:

Protocol1 myProtocol; 
myProtocol << myMiddleTierMessage; 

Использование operator<< для такого рода операций хорошо известно и очень распространено. Кроме того, он дает вам очень гибкий подход: не все сообщения необходимы для реализации всех протоколов.

Недостатком является то, что он не будет работать для динамического выбора выходного протокола. В этом случае вы можете использовать более гибкий подход. Попробовав различные решения, я решил использовать шаблон стратегии с регистрацией времени компиляции.

Идея состоит в том, что я использую Singleton, который содержит несколько объектов Functor. Каждый объект зарегистрирован (в данном случае) для конкретной комбинации Message - Protocol. В этой ситуации это очень хорошо работает.


Наконец, для BOM -> MiddleTier шага, я бы сказал, что конкретный экземпляр Message должен знать, как строить себя и должен требовать необходимых объектов в рамках своего конструктора.

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


Складывая все это вместе.

// 1 - Your BOM 
class Foo {}; 
class Bar {}; 

// 2 - Message class: GetUp 
class GetUp 
{ 
    typedef enum {} State; 
    State m_state; 
}; 

// 3 - Protocl class: SuperProt 
class SuperProt: public Protocol 
{ 
}; 

// 4 - GetUp to SuperProt serializer 
class GetUp2SuperProt: public Serializer 
{ 
}; 

// 5 - Let's use it 
Foo foo; 
Bar bar; 

SuperProt sp; 
GetUp getUp = GetUp(foo,bar); 

MyMessage2ProtBase.serialize(sp, getUp); // use GetUp2SuperProt inside 
+0

Я приму это для полноты и усилий, охватывающих множество углов .. ура.однако, я не вижу, чтобы стандарты стандартов кодирования не вводили друга, и пока я не могу пригвоздить его, я немного неохотно поеду за ним. Возможно, он ошибается, но должен сначала увидеть. –

+0

http://www.gotw.ca/publications/c++cs.htm> Пункт 44. Идея состоит в том, чтобы способствовать лучшей инкапсуляции, поскольку функции членов и друзей восприимчивы к изменениям внутренней работы одного класса, в то время как nonmember nonfriend функций нет (они зависят только от общедоступных методов). –

2

Если вам нужно много выходных форматов для многих классов, я хотел бы попробовать сделать это в + m вместо задачи n * m. Первый способ, который я придумал, - показать классы, которые могут быть переведены в какой-то словарь, а затем иметь способ серлализовать эти словари для каждого выходного формата.

+0

+1 для масштабируемости точка зрения .. –

1

Я использовал OpenH323 (достаточно известный для разработчиков VoIP) библиотеку на достаточно длительный срок для создания количества приложений, связанных с VoIP, начиная с автоответчика с низкой плотностью и до 32xE1 пограничного контроллера. Конечно, это была серьезная переделка, поэтому я знал почти что-нибудь об этой библиотеке в те дни.

Внутри этой библиотеки был инструмент (ASNparser), который преобразовывал определения ASN.1 в классы контейнеров. Также была структура, которая позволяла сериализовать/де-сериализовать эти контейнеры, используя абстракции более высокого уровня. Обратите внимание, что они автоматически генерируются. Они поддерживали несколько протоколов кодирования (BER, PER, XER) для ASN.1 с очень сложным sntax ASN и достаточно хорошей производительностью.

Что было хорошего?

  • Автогенерируемые классы контейнеров, которые были достаточно подходящими для реализации четкой логики.
  • Мне удалось переработать весь контейнерный слой под иерархией объектов ASN без каких-либо изменений для верхних слоев.
  • Было относительно легко сделать рефакторинг (производительность) для отладочных функций этих классов ASN (я понимаю, авторы не собирались ожидать, что сигнализация вызовов 20xE1 будет регистрироваться в сети).

Что не подходит?

  • Не-STL-библиотека с ленивой копией в соответствии с этим. Рефакторинг по скорости, но я бы хотел иметь совместимость с STL (по крайней мере, в то время).

Вы можете найти Wiki-страницу всего проекта here. Вы должны сосредоточиться только на компонентах PTlib, источниках анализатора ASN, иерархии политик иерархии/кодирования/декодирования классов ASN.

Кстати, оглянитесь вокруг шаблона дизайна «Мост», это может быть полезно.

Не стесняйтесь комментировать вопросы, если что-то странное/недостаточно/не то, что вы запросили actall.

+0

спасибо .. и все оценили, +1. Я всегда делаю фазу upvote сначала для перспективы (и их много) или усилий, и больше вопросов, возможно, позже. –

1

Предполагая, что у вас есть полный доступ к классам, которые должны быть сериализованы. Вы должны добавить некоторую форму отражения в классы (возможно, включая абстрактный завод). Существует два способа сделать это: 1) общий базовый класс или 2) структура «признаков». Затем вы можете написать свои кодировщики/декодеры в отношении структуры базового класса/признаков.

В качестве альтернативы вы можете потребовать, чтобы класс предоставлял функцию для экспорта в контейнер boost :: any и предоставлял конструктор, который принимает значение boost :: any container как единственный параметр. Простое создание функции сериализации для разных форматов, если исходные данные хранятся в карте boost :: any objects.

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

+0

+1 для повышения, поскольку я почти считаю его частью языка .. и, конечно, для угла подобия/разнесения. –

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