Есть некий класс с десятком полей данных. Хочется объекты этого класса сохранять в какое-то хранилище и загружать из него. Но из-за некоторых особенностей не могу придумать архитектуру этого процесса.
Жизненный цикл этого объекта выглядит примерно так:
1. Экземпляр класса создается в памяти. Заполняется, предположим, 5 полей. Сохраняется в основное хранилище.
2. (опционально) Экземпляр класса создается в памяти. Первые 5 полей заполняются из основного хранилища, редактируются и сохраняются обратно в основное хранилище.
3. Экземпляр класса создается в памяти. Первые 5 полей заполняются из основного хранилища. Вторые 5 полей тоже чем-то заполняются. Объект сохраняется в дополнительное хранилище.
4. (опционально) Экземпляр класса создается в памяти. Все поля заполняются из дополнительного хранилища. Вторые 5 полей редактируются. Объект сохраняется в дополнительное хранилище.
(Пункты 2 и 4 могут присутствовать один или несколько раз, а могут вообще не присутствовать.)
А особенности такие:
— Хотелось бы, чтобы пункты 1 и 2 были реализованы в одном приложении, а 3 и 4 — в другом.
— Процесс чтения и сохранения в основное и дополнительные хранилища разный. У них разная структура, и даже одни и те же поля будут сохраняться туда по-разному.
— Хотелось бы иметь возможность в качестве основного и дополнительного хранилища использовать файлы разных форматов. Сейчас есть планы на sqlite, но потом хотелось бы добавить, например, xml и обычный текстовый файл.
— В связи с этим хотелось бы обеспечить максимальную модульность программы и минимальное количество связей между классами.
Да! Пишу на С++, если это важно.
Заранее спасибо за ответы.
X>Гуглить на слово "сериализация". Опционально можно посмотреть паттерны builder и prototype.
Я извиняюсь за наглость, но всё равно остались вопросы по поводу конкретного применения.
Насколько я понимаю (глядя в mfc), сериализация — это что-то типа:
При нескольких форматах файла да, это может помочь — видимо, надо отнаследоваться от одного базового класса-архива и в классах-потомках сохранять в разные форматы.
Но как она мне поможет при нескольких вариантах сохранения? Когда в одно время надо сохранять my_data1 и my_data2, а в другое — my_data3, my_data4 и их сумму куда-то в третье место.
А если этих форматов архивов будет 10? Или 20? На каждый вариант свою функцию писать? Может быть, можно как-то покомпактнее сделать?
К тому же, такая архитектура преподлагает то, что MyClass должен знать о каждом типе архива, в который он сохраняется. По моему скромному мнению, это довольно криво.
Ну тут надо решать: либо обьект знает обо всех архивах (т.е. форматах
сохранения) либо архив знает обо всех объектах которые в него можно
записать. В любом случае мне кажется, что логично каждый тип архива надо
наследовать от архива-родителя, чтобы код в итоге по-приличнее выглядел.
Здравствуйте, Cruelty, Вы писали:
C>Ну тут надо решать: либо обьект знает обо всех архивах (т.е. форматах C>сохранения) либо архив знает обо всех объектах которые в него можно C>записать. В любом случае мне кажется, что логично каждый тип архива надо C>наследовать от архива-родителя, чтобы код в итоге по-приличнее выглядел.
Типов архивов может быть много. А типов объектов, которые туда записывается — максимум штук 5.
А про наследование понятно. Но, если вы читали первоначальное письмо, вопрос был не в этом. Там было описано, что должна быть возможность сохранять в несколько разных форматов файлов и с использованием нескольких схем сохранения. Вопрос был в том, как организовать именно это.
Здравствуйте, Ilias, Вы писали:
I> как организовать именно это.
Если объектов мало, добавлять новые не будут, типов архивов много и их будут постоянно добавлять/менять/удалять, то можно делать так:
class CObType1;
class CObType2;
class CArchiveBase
{
virtual void Save(const CObType1* pOb) = 0;
virtual void Save(const CObType2* pOb) = 0;
};
class CArchive1 : public
{
virtual void Save(const CObType1* pOb);
virtual void Save(const CObType2* pOb);
};
class CArchive2
{
virtual void Save(const CObType1* pOb);
virtual void Save(const CObType2* pOb);
};
class CArchiveBase;
class CSerialisableObject
{
virtual Serialise(CArchiveBase* pAr) = 0;
virtual int GetObjectId();
virtual int GetObjectVersion();
};
class CObType1 : public CSerialisableObject
{
virtual Serialise(CArchiveBase* pAr)
{
pAr->Save(this);
}
};
Тогда изменение/добавление архива вызовет перекомпиляцию только етого архива, удаление не повлияет на компиляцию. Но изменеие любого обьекта приведет к перекомпиляции мира.
Если же объекты тоже меняются, то я бы делал не самопальную сериализацию, а использовал boost::serialization с его великолепной поддержкой версионности, наследования, сериализации смарт-поинтеров и контейнеров. И не такая уже и беда, если обьект знает как сохранять себя в каждом взятом формате.
Здравствуйте, Cruelty, Вы писали:
C>Здравствуйте, Ilias, Вы писали:
I>> как организовать именно это.
C>Если объектов мало, добавлять новые не будут, типов архивов много и их будут постоянно добавлять/менять/удалять, то можно делать так:
Вы явно не прочитали первоначальное сообщение. Напишу в третий раз — может быть несколько форматов файлов для сохранения, а так же — может быть несколько схем сохранения.
Формат файла — это значит, что данные могут сохраняться в базу данных (sqlite для начала), xml-файл, еще какие-то форматы, и т.д.
Схема сохранения — это значит, что при использовании схемы 1 будут сохранены MyClass.data1, и MyClass.data2, а при использовании схемы 2 будут сохранены MyClass1.data3, MyClass.data4 и MyClass.data8.
Необходимо реализовать все сочетания форматов файлов и схем сохранения.
Здравствуйте, Ilias, Вы писали:
I>Здравствуйте, Cruelty, Вы писали:
C>>Здравствуйте, Ilias, Вы писали:
I>>> как организовать именно это.
C>>Если объектов мало, добавлять новые не будут, типов архивов много и их будут постоянно добавлять/менять/удалять, то можно делать так:
I>Вы явно не прочитали первоначальное сообщение. Напишу в третий раз — может быть несколько форматов файлов для сохранения, а так же — может быть несколько схем сохранения. I>Формат файла — это значит, что данные могут сохраняться в базу данных (sqlite для начала), xml-файл, еще какие-то форматы, и т.д. I>Схема сохранения — это значит, что при использовании схемы 1 будут сохранены MyClass.data1, и MyClass.data2, а при использовании схемы 2 будут сохранены MyClass1.data3, MyClass.data4 и MyClass.data8. I>Необходимо реализовать все сочетания форматов файлов и схем сохранения.
data1, data2, ... , dataN.
Если N невелико — достаточно будет в метод сериализации передавать параметр из битовых флагов.
Здравствуйте, Ilias, Вы писали:
I>Здравствуйте, Cruelty, Вы писали:
C>>Здравствуйте, Ilias, Вы писали:
I>>> как организовать именно это.
C>>Если объектов мало, добавлять новые не будут, типов архивов много и их будут постоянно добавлять/менять/удалять, то можно делать так:
I>Вы явно не прочитали первоначальное сообщение. Напишу в третий раз — может быть несколько форматов файлов для сохранения, а так же — может быть несколько схем сохранения. I>Формат файла — это значит, что данные могут сохраняться в базу данных (sqlite для начала), xml-файл, еще какие-то форматы, и т.д. I>Схема сохранения — это значит, что при использовании схемы 1 будут сохранены MyClass.data1, и MyClass.data2, а при использовании схемы 2 будут сохранены MyClass1.data3, MyClass.data4 и MyClass.data8. I>Необходимо реализовать все сочетания форматов файлов и схем сохранения.
Вы кагда-нибудь слышали про множественное наследование (горяче любимые некоторыми policy)? Два базовых архивных класса: один ответственный за формат, а второй за схему. И их уже можно скресчивать как угодно.
C>Вы кагда-нибудь слышали про множественное наследование (горяче любимые некоторыми policy)? Два базовых архивных класса: один ответственный за формат, а второй за схему. И их уже можно скресчивать как угодно.
Слышал. Но как здесь применить множественное наследование — не совсем понимаю. Если Вы сможете написать ма-а-аленький примерчик — буду очень признателен.
Здравствуйте, Cruelty, Вы писали:
C>Здравствуйте, Ilias, Вы писали:
I>> Если Вы сможете написать ма-а-аленький примерчик — буду очень признателен.
C>Можно так: просто и без выкрутасов. Опять повторяюсь, если типов объектов мало и они не будут добавляться/меняться.
Не, это вполне нормально. Примерно так я и хотел сделать, но пытался выяснить нет ли других, более элегантных способов. Только где ж тут множественное наследование?
Здравствуйте, Ilias, Вы писали:
I>Здравствуйте, Cruelty, Вы писали:
C>>Здравствуйте, Ilias, Вы писали:
I>>> Если Вы сможете написать ма-а-аленький примерчик — буду очень признателен.
C>>Можно так: просто и без выкрутасов. Опять повторяюсь, если типов объектов мало и они не будут добавляться/меняться.
I>Не, это вполне нормально. Примерно так я и хотел сделать, но пытался выяснить нет ли других, более элегантных способов. Только где ж тут множественное наследование?
Извиняюсь -- был занят потому и написал такой пример по-быстрому. Вот со множественным наследованием: