"Сериализация" объектов проекта. (destination сериализации на этапе разработки неизвестен)

Модератор: Модераторы разделов

Аватара пользователя
Zeus
Сообщения: 694

"Сериализация" объектов проекта.

Сообщение Zeus »

Задача: в проекте есть набор классов со сложной внутренней структурой.
Требуется реализовать принцип сохранения состояния объектов этих классов и восстановления этого состояния.
Проблема только, что сейчас ещё неизвестно куда они будут сохраняться: XML, база данных (тоже неизвестно какая), может ещё что - а может нужно предложить пользователю все возможные варианты, чтобы сам выбрал.
Вполне возможно, что будут появляться новые варианты уже после разработки и передачи системы заказчику.
Т.е. сама операция "сохранения" (сериализации) будет реализована уже после реализации (и даже компиляции в проект) классов.
Видимо это будет в виде shared library реализовано, но вот как его "внедрить" в архитектуру проектов на уровне классов

Была мысль перегрузить operator>> и operator<< для каждого класса, причём несколько раз (для XML, для MYSQL*, PGSQL* и т.п.).
Но тогда не получается реализовать идеологию c shared library: эти операторы же уже должны быть известны на стадии компиляции проекта.

Никто похожими мыслями не озадачивался? Как решали?
Спасибо сказали:
v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Re: "Сериализация" объектов проекта.

Сообщение v04bvs »

Код: Выделить всё

 abstract class AbstractSerializator {
     public abstract void save(String name, int value);
     public abstract void save(String name, double value);
     public abstract void save(String name, Object value);
 }

 interface Serializable {
     void serialize(AbstractSerializator serializator);
 }

 class Hero implements Serializable {
     private double health;
     private int strength;
     private String name;

     public void serialize(AbstractSerializator serializator) {
         serializator.save("health", health);
         serializator.save("strength", strength);
         serializator.save("name", name);
     }
 }


Принцип думаю понятен.
Спасибо сказали:
sergio
Сообщения: 436
Статус: Интересующийся новичок
ОС: Debian GNU/Linux 4 & 5

Re: "Сериализация" объектов проекта.

Сообщение sergio »

Основных подхода видется два.
Либо мы сохраняем всю структуру в "универсальный" формат (ХМЛ), плагин-конвертер (один из) его получает, пишет целиком как есть в... (файл, сокет, BLOB и т.д.) или берет хмл-евую либу, проходит и делает-конвертирует чего надо (раскладывает по полям для SQL и т.д.)
Второй вариант - задействуем стандартный дизайн-темплейт, когда относительно "корня" структуры вызывается метод, ему передается ссылка на интерфейс,

Код: Выделить всё

class Worker {
  virtual  void process(const TypeA&)  = 0;
  virtual  void process(const TypeB&)  = 0;
  virtual  void process(const TypeC&)  = 0;
};

и метод обеспечивает рекурсивный обход своего дерева, передавая каждый элемент интерфейсу.

Код: Выделить всё

w.process(* this);

или

Код: Выделить всё

w.process(this->_number);

Оч примерное описание, нормальное было в книжке у "Банды четырех".
Ограничение - структура может быть любой, но набор элементов из которых она состоит, должен быть постоянен (к моменту разработки Worker-ов), иначе придется править-пересобирать их все. Ограничений на способы обработки структуры соотв-но нет.

У operator << есть один недостаток: он всегда бинарен. Его нельзя перегрузить по дополнительному аргументу, нужно всегда плодить детей ostream. Кроме того, применение его с чем-то кроме istream+/ostream+ - уже дурной тон, пожалуй. А в общем случае, ничего кроме совместимости std::i/o-stream_iterator это не дает. Так что на мой вкус правильнее решение типа

S& write(S& out, const T& obj) { return obj.write(out) ; }
и
virtual S& T::write(S&) const ;
соотв-но. К этой бурде можно доделать перегруженный по доп.аргументу (state, format etc.) всегда...
Debian GNU/Linux 4 -- AMD Athlon64 3000+ / Asus 7600GS -- Gnome
Debian GNU/Linux 5 -- Dell (Vostro) 500 (Celeron M560 / iGM965) -- Gnome
Спасибо сказали:
Аватара пользователя
Zeus
Сообщения: 694

Re: "Сериализация" объектов проекта.

Сообщение Zeus »

Спасибо за советы.

Мысль с плагином-конвертером понравилась.
"Научить" классы сохраняться/читаться (хоть операторами, хоть save/load'ами) из древовидной структуры, типа этой: XML парсер в DOM tree. C++
а потом - только и делай, что конвертеры пиши :)

Боюсь только, не слишком ли расточительны будут все эти преобразования туда-сюда при большом количестве данных?

Может лучше всё-таки сделать абстрактный базовый класс saver/loader, а в shared libraries реализовывать его наследников для всяких разных случаев (XML, база, файл, сокет), которые, зная структуру класса-хранилища, будут напрямую шастать по его потрохам и сохранять данные?

А что там про недостаток операторов << / >>?
Про унарность - понятно.
А про детей и итераторы что-то недопонял :unsure:
Спасибо сказали:
sergio
Сообщения: 436
Статус: Интересующийся новичок
ОС: Debian GNU/Linux 4 & 5

Re: "Сериализация" объектов проекта.

Сообщение sergio »

Zeus писал(а):
21.09.2007 14:35
а потом - только и делай, что конвертеры пиши :)

Главное - все не проклясть при этом процессе, если его делать приде тся тебе же. :happy:

А что там про недостаток операторов << / >>?


Код: Выделить всё

enum { TEXT_SUMMARY, FULL_DUMP, TEXT_XML };
template <int N> class FormatTag {  };

write(std::cout, my_obj, FormatTag<TEXT_SUMMARY>());
write(std::cerr, my_obj, FormatTag<FULL_DUMP>());
std::ofstream ou("file.xml");
write(ou, my_obj, FormatTag<TEXT_XML>());


Примерно так. А с operator << мы ограничены одним вариантом. Для остальных надо или давать другие имена функциям/методам (соотв-но плачет однообразие и кое-где шаблоны), или плодить производные классы "потока вывода", что иногда само-собой в любом случае приходится делать, а иногда и вовсе ни к чему. А вешание вывода на operator << вроде б позволяет из стандартной либы только вот это задейстововать:

Код: Выделить всё

std::copy(container.begin(), container.end(), std::ostream_iterator<Type>(cout, ", ");

Не могу сообразить, что в стдлиб это где-то еще применялось.
Одним словом - вопрос вкуса и задачи. Можно так, можно этак.

Если не ХМЛ а код, имхо главное - сообразить, как построить интерфейс. Т.е. вопрос, может ли внешний код, который получает структуру для вывода, сам по ней пройти, или его нужно проводить вызывая для элемента; есть ли аксесс-методы ко всем данным, которые ему нужны, или объект должен скармливать ему данные сам поштучно; плюс надо отобразить иерархию - т.е. о перемещении по дереву конвертор должен получать информацию тоже, если не сам по дереву идет, т.е. типа:

Код: Выделить всё

SomeNode::serialize(Serializer s)  {
  s.beginNode(this->_class_id);
  for each child
    child.serialize(s);
  s.endNode();


Плюс надо сразу думать о обратном процессе, но скорее всего не проще. :happy:
Debian GNU/Linux 4 -- AMD Athlon64 3000+ / Asus 7600GS -- Gnome
Debian GNU/Linux 5 -- Dell (Vostro) 500 (Celeron M560 / iGM965) -- Gnome
Спасибо сказали: