2013-05-21 2 views
1

Я попытался внимательно прочитать все советы, приведенные в C++FAQ на эту тему. Я внедрил свою систему в соответствии с пунктом 36.8 и теперь, спустя несколько месяцев (с большим количеством сериализуемых данных), я хочу внести изменения как в общий интерфейс некоторых классов, так и в структуру наследования.Как выполнить гибкую сериализацию полиморфной иерархии наследования?

class Base 
{ 
public: 
    Vector field1() const; 
    Vector field2() const; 
    Vector field3() const; 
    std::string name() const {return "Base";} 
}; 

class Derived : public Base 
{ 
public: 
    std::string name() const {return "Derived";} 
}; 

Я хотел бы знать, как сделать такие изменения, как:

  1. Split Derived в Derived1 и Derived2, в то время как отображение исходной Derived в Derived1 для существующих данных.

  2. Split Base::field1() в Base::field1a() и Base::field1b() в то время как отображение field1 в field1a и с field1b пустой для существующих данных.

мне придется

  1. десериализации все гигабайты моих старых данных
  2. преобразовать их в новую структуру наследования
  3. reserialize их в новом и более гибко.

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

Я думал о создании системы, которая использовала бы цифры вместо имен для сериализации моих объектов. Это, например, Base = 1, Derived1 = 2, ... и отдельная номер-к-имени система, которая конвертирует числа в имена, так что когда я хочу изменить имя какого-либо класса, я бы делайте это только в этой отдельной системе номер-имени, не меняя данные.

Проблемы, связанные с этим подходом являются:

  1. Система будет хрупкими. То, что меняет что-либо в системе номер-к-имени, может изменить смысл гигабайт данных.

  2. Сериализованные данные потеряют некоторые из его человеко-читаемость, так как в сериализованных данных вместо имен будут цифры.

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

Любые общие материалы, учебники, идиомы или литература по гибкой сериализации наиболее приветствуются!

+2

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

+1

Отображение не обязательно должно быть 1: 1, вы можете написать 'class NewWidget' как« NewWidget », но прочитать« Виджет »и« NewWidget »как« класс NewWidget ». Кроме того, если поле имеет разумное значение по умолчанию, вы просто используете его, когда его значение не встречается в сериализованных данных. Таким образом, вы можете вводить новые поля без особых проблем. Это автоматически покрывает 90% ваших потребностей. –

+1

Для остальных 10 процентов вам потребуется написать код конверсии. Просто никогда не удаляйте старые классы и поля из вашего кода. Напишите для них процедуры пост-десериализации, которые преобразуют их в новые объекты. –

ответ

2

Возможно, это немного поздно для этого, но при проектировании формата сериализации вы должны предоставить версию. Это может быть искажено в информации о типе в потоке, или рассматривается как отдельное (целочисленное) поле. При записи класса вы всегда пишете последнюю версию. Когда вы читаете, вы должны должны прочитать как тип, так и версию, прежде чем вы сможете построить ; если вы используете статическую карту, предложенную в FAQ, то ключ будет:

struct DeserializeKey 
{ 
    std::string type; 
    int version; 
}; 

Учитывая ситуацию вы в настоящее время, решение возможно искажать версию во имя типа в четко узнаваемый способ сказать что-то по строкам type_name__version; если после не следует двух знаков подчеркивания, , то используйте 0. Это не самый эффективный метод, но обычно это , и он будет решать проблему с обратной совместимостью, обеспечивая при этом эволюцию в будущем.

Для ваших точных вопросов:

  1. В этом случае Derived только предыдущая версия Derived1. Вы можете вставить необходимую заводскую функцию в карту под соответствующим ключом.

  2. Это просто классическая версия. Версия 0 Base имеет атрибут a field1, а когда вы deserialize, вы используете его для , инициализируете field1a, и вы инициализируете field1b пустым. Версия 2 из Base имеет оба.

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

+0

Спасибо! Это именно то, что мне нужно было слышать. –

0

возможно Thrift Может помочь вам это сделать.

+0

Спасибо, но ваша ссылка кажется слишком продвинутой для меня. Я не знаю, о чем они говорят :( –

+1

@MartinDrozdik Это похоже на то, что приходит вам слишком поздно. (Также есть блоки протокола Google). Обычно код сериализации _is_ генерируется, а не написан вручную, и генератор позаботится обо всех проблемах, о которых я упоминаю в своем ответе, но вероятность того, что вы обнаружите генератора, который каким-то чудесным образом генерирует именно тот формат, который вы используете, кажется мне довольно маленьким. –

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