сериализация - создание при чтении
От: Pavel Anufrikov Россия  
Дата: 11.10.06 06:31
Оценка:
Давно мучает вопрос, не могу найти элегантного решения.

Есть несколько классов с общим предком. В хранилище есть объект одного из этих классов (неизвестно, какого именно). Необходимо загрузить данные из файла.

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

Вопрос в чем: все ли здесь верно с точки зрения построения архитектуры? Как решаются такие вопросы в системах сериализации?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: сериализация - создание при чтении
От: Sergey Россия  
Дата: 11.10.06 07:35
Оценка: 2 (1)
> Давно мучает вопрос, не могу найти элегантного решения.

Язык какой? Элегантность/не элегантность часто зависит от средств, которыми допустимо пользоваться.

> Есть несколько классов с общим предком. В хранилище есть объект одного из этих классов (неизвестно, какого именно). Необходимо загрузить данные из файла.

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

Ну фабрика для создания объектов потребуется в любом случае (желательно, встроенная в язык ). А вот объект-хозяин — не обязательно.

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

>
> Вопрос в чем: все ли здесь верно с точки зрения построения архитектуры?

Недостаточно гибкая архитектура, на мой взгляд. Зачем объект-хозяин должен хранить указатель на созданный объект и заниматься уничтожением объекта? Ведь ты грузишь объект куда-то — вот там, куда загрузил, его можно и уничтожать впоследствии.

> Как решаются такие вопросы в системах сериализации?


Скажем, в boost::serialization данная задача решена так:
Есть глобальная фабрика, умеющая по некоему описателю типа создавать объект (описатель типа тоже является сериализуемым объектом). Есть классы архивов, отдельно input_archive, отдельно output_archive, умеющие читать-писать объекты. Сериализуемый тип предоставляет некий интерфейс для сериализации, о котором знает архив (перегруженные функции serialize для встроенных типов и классов или функции-члены serialize для классов). Объект сохраняется вызовом метода архива (операторы <<, >> или &). Архив при необходимости (если класс сериализуется полиморфно) регистрирует класс в фабрике и записывает/читает в стрим сначала описатель типа (и версию, кстати), потом данные класса. На время загрузки созданными объектами владеет архив (чтобы прибить их в случае возникновения исключений), потом владение передается тому коду, который и вызвал сериализацию. Архив так же отвечает за то, в каком формате писать данные в стрим — просто есть несколько пар архивов, для бинарной, текстовой, xml сериализации.
Posted via RSDN NNTP Server 2.0
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re: сериализация - создание при чтении
От: Gangsta  
Дата: 11.10.06 14:20
Оценка:
Здравствуйте, Pavel Anufrikov, Вы писали:

PA>Есть несколько классов с общим предком. В хранилище есть объект одного из этих классов (неизвестно, какого именно). Необходимо загрузить данные из файла.


PA>Создать объект и вызвать у него .load() нельзя, т.к. неизвестен его тип.


А почему нельзя создать один класс, от которого унаследовать все твои классы. Подклассы будут переопределять метод load — вот и все. Подробнее см. паттерн "Шаблонный метод".
Re[2]: сериализация - создание при чтении
От: Pavel Anufrikov Россия  
Дата: 12.10.06 04:16
Оценка:
Здравствуйте, Gangsta, Вы писали:

G>А почему нельзя создать один класс, от которого унаследовать все твои классы. Подклассы будут переопределять метод load — вот и все. Подробнее см. паттерн "Шаблонный метод".


Не совсем понял. У них один предок, только при загрузке тип объекта еще не известен. Вопрос как раз в том, кто должен владеть таким объектом, читать его тип, создавать, вызывать его загрузку.
Re[2]: сериализация - создание при чтении
От: Pavel Anufrikov Россия  
Дата: 12.10.06 04:17
Оценка:
S>Язык какой? Элегантность/не элегантность часто зависит от средств, которыми допустимо пользоваться.

C++

S>Ну фабрика для создания объектов потребуется в любом случае (желательно, встроенная в язык ). А вот объект-хозяин — не обязательно.


Вопрос тогда такой: кто должен заниматься чтением/записью типа объекта в/из контейнер(а)?

S>Недостаточно гибкая архитектура, на мой взгляд. Зачем объект-хозяин должен хранить указатель на созданный объект и заниматься уничтожением объекта? Ведь ты грузишь объект куда-то — вот там, куда загрузил, его можно и уничтожать впоследствии.


Предполагалось, что хозяин полностью владеет объектом и уничтожает его в своем деструкторе. Создает же объект в методе загрузки, после чтения идентификатора типа. Муть?

S>Скажем, в boost::serialization данная задача решена так:

S>Есть глобальная фабрика, умеющая по некоему описателю типа создавать объект (описатель типа тоже является сериализуемым объектом). Есть классы архивов, отдельно input_archive, отдельно output_archive, умеющие читать-писать объекты. Сериализуемый тип предоставляет некий интерфейс для сериализации, о котором знает архив (перегруженные функции serialize для встроенных типов и классов или функции-члены serialize для классов). Объект сохраняется вызовом метода архива (операторы <<, >> или &). Архив при необходимости (если класс сериализуется полиморфно) регистрирует класс в фабрике и записывает/читает в стрим сначала описатель типа (и версию, кстати), потом данные класса. На время загрузки созданными объектами владеет архив (чтобы прибить их в случае возникновения исключений), потом владение передается тому коду, который и вызвал сериализацию. Архив так же отвечает за то, в каком формате писать данные в стрим — просто есть несколько пар архивов, для бинарной, текстовой, xml сериализации.

Не понятно, как идеологически правильно: можно сделать, чтобы архив умел сохранять объекты в нужный формат, тогда нужно учить архив работать с разными типами объектов. Можно сделать, чтобы объекты сами умели сохраняться в архив, тогда нужно делать, чтобы они умели сохраняться в архивы разных типов. Кто должен владеть этим кодом?
Re[3]: сериализация - создание при чтении
От: Sergey Россия  
Дата: 12.10.06 08:22
Оценка: 2 (1)
>S>Язык какой? Элегантность/не элегантность часто зависит от средств, которыми допустимо пользоваться.
>
> C++
>
> S>Ну фабрика для создания объектов потребуется в любом случае (желательно, встроенная в язык ). А вот объект-хозяин — не обязательно.
>
> Вопрос тогда такой: кто должен заниматься чтением/записью типа объекта в/из контейнер(а)?

Все точно так же, как и при сериализации любого другого объекта. Код из буста выглядит так:


template<class Archive, class Container>
struct archive_input_seq
{
inline void operator()(Archive &ar, Container &s)
{
detail::stack_construct<Archive, BOOST_DEDUCED_TYPENAME Container::value_type> t(ar);
// borland fails silently w/o full namespace
ar >> boost::serialization::make_nvp("item", t.reference());
s.push_back(t.reference());
ar.reset_object_address(& s.back() , & t.reference());
}
};
template<class Archive, class U, class Allocator>
inline void load(
Archive & ar,
STD::vector<U, Allocator> &t,
const unsigned int /* file_version */
){
boost::serialization::stl::load_collection<
Archive,
STD::vector<U, Allocator>,
boost::serialization::stl::archive_input_seq<
Archive, STD::vector<U, Allocator> 
>,
boost::serialization::stl::reserve_imp<STD::vector<U, Allocator> >
>(ar, t);
}


Если повыкидывать несущественные для понимания сути подробности и тонкости, то останется примерно следующее:
template<class Archive, class U, class Allocator>
inline void load(Archive & ar, STD::vector<U, Allocator> &t, const unsigned int /* file_version */)
{
    std::size_t count;
    ar >> count;
    t.reserve(count);
    while (count--)
    {
        U v;
        ar >> boost::serialization::make_nvp("item", v);
        t.push_back(v);
    }
}


>

> S>Недостаточно гибкая архитектура, на мой взгляд. Зачем объект-хозяин должен хранить указатель на созданный объект и заниматься уничтожением объекта? Ведь ты грузишь объект куда-то — вот там, куда загрузил, его можно и уничтожать впоследствии.
>
> Предполагалось, что хозяин полностью владеет объектом и уничтожает его в своем деструкторе. Создает же объект в методе загрузки, после чтения идентификатора типа. Муть?

Просто неудобно. Допустим, у меня в программе где-то в качестве члена класса используется std::vector<boost::shared_ptr<MyClass> >; Фактически, после загрузки его из файла вашим способом я буду вынужден скопировать его из "объекта-хозяина сериализации" в тот объект, которому он реально нужен, а потом попросить "объект-хозяина сериализации" уничтожить старую копию — поскольку она больше не нужна. Зачем это писать каждый раз, когда это вполне разумное действие можно сделать дефолтным?

> Не понятно, как идеологически правильно: можно сделать, чтобы архив умел сохранять объекты в нужный формат, тогда нужно учить архив работать с разными типами объектов. Можно сделать, чтобы объекты сами умели сохраняться в архив, тогда нужно делать, чтобы они умели сохраняться в архивы разных типов. Кто должен владеть этим кодом?


Архивы умеют сохранять только примитивные типы, а сами объекты либо умеют сохраняться в любой из архивов, предоставляя шаблонные функции save/load/serialize, либо умеют сериализоваться в конкретный тип архива (а им может быть, например, polymorphic_iarchive/polymorphic_oarchive, от которых унаследованы polymorphic_binary_iarchive, polymorphic_text_iarchive, polymorphic_xml_iarchive). Вообще, лучше доку соответствующую посмотрите — там все понятно написано.
Posted via RSDN NNTP Server 2.0
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.