Чтение уже опубликованных ответов, я могу согласиться только на подход среднего уровня.
В принципе, в исходной задаче у вас есть 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
Я приму это для полноты и усилий, охватывающих множество углов .. ура.однако, я не вижу, чтобы стандарты стандартов кодирования не вводили друга, и пока я не могу пригвоздить его, я немного неохотно поеду за ним. Возможно, он ошибается, но должен сначала увидеть. –
http://www.gotw.ca/publications/c++cs.htm> Пункт 44. Идея состоит в том, чтобы способствовать лучшей инкапсуляции, поскольку функции членов и друзей восприимчивы к изменениям внутренней работы одного класса, в то время как nonmember nonfriend функций нет (они зависят только от общедоступных методов). –