сохранение/загрузка
От: Ilias  
Дата: 03.01.06 11:46
Оценка:
Есть некий класс с десятком полей данных. Хочется объекты этого класса сохранять в какое-то хранилище и загружать из него. Но из-за некоторых особенностей не могу придумать архитектуру этого процесса.

Жизненный цикл этого объекта выглядит примерно так:
1. Экземпляр класса создается в памяти. Заполняется, предположим, 5 полей. Сохраняется в основное хранилище.
2. (опционально) Экземпляр класса создается в памяти. Первые 5 полей заполняются из основного хранилища, редактируются и сохраняются обратно в основное хранилище.
3. Экземпляр класса создается в памяти. Первые 5 полей заполняются из основного хранилища. Вторые 5 полей тоже чем-то заполняются. Объект сохраняется в дополнительное хранилище.
4. (опционально) Экземпляр класса создается в памяти. Все поля заполняются из дополнительного хранилища. Вторые 5 полей редактируются. Объект сохраняется в дополнительное хранилище.

(Пункты 2 и 4 могут присутствовать один или несколько раз, а могут вообще не присутствовать.)

А особенности такие:
— Хотелось бы, чтобы пункты 1 и 2 были реализованы в одном приложении, а 3 и 4 — в другом.
— Процесс чтения и сохранения в основное и дополнительные хранилища разный. У них разная структура, и даже одни и те же поля будут сохраняться туда по-разному.
— Хотелось бы иметь возможность в качестве основного и дополнительного хранилища использовать файлы разных форматов. Сейчас есть планы на sqlite, но потом хотелось бы добавить, например, xml и обычный текстовый файл.
— В связи с этим хотелось бы обеспечить максимальную модульность программы и минимальное количество связей между классами.

Да! Пишу на С++, если это важно.
Заранее спасибо за ответы.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: сохранение/загрузка
От: xtile  
Дата: 09.01.06 03:12
Оценка:
Здравствуйте, Ilias, Вы писали:

Гуглить на слово "сериализация". Опционально можно посмотреть паттерны builder и prototype.
Re[2]: сохранение/загрузка
От: Ilias  
Дата: 09.01.06 09:58
Оценка:
X>Гуглить на слово "сериализация". Опционально можно посмотреть паттерны builder и prototype.

Я извиняюсь за наглость, но всё равно остались вопросы по поводу конкретного применения.
Насколько я понимаю (глядя в mfc), сериализация — это что-то типа:

MyClass::Serialize(Archive& archive)
{
    if(archive.IsStoring())
    {
        archive << my_data1;
        archive << my_data2;
        ...
    }
    else
    {
        archive >> my_data1;
        archive >> my_data2;
        ...
    }
}


При нескольких форматах файла да, это может помочь — видимо, надо отнаследоваться от одного базового класса-архива и в классах-потомках сохранять в разные форматы.
Но как она мне поможет при нескольких вариантах сохранения? Когда в одно время надо сохранять my_data1 и my_data2, а в другое — my_data3, my_data4 и их сумму куда-то в третье место.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: сохранение/загрузка
От: Cruelty  
Дата: 10.01.06 12:48
Оценка:
Завести несколько типов архивов и в каждый записывать то что надо етому
архиву.
Posted via RSDN NNTP Server 2.0
Re[4]: сохранение/загрузка
От: Ilias  
Дата: 10.01.06 14:33
Оценка:
Здравствуйте, Cruelty, Вы писали:

C>Завести несколько типов архивов и в каждый записывать то что надо етому

C>архиву.

Т.е. вы предлагаете сделать примерно так?

MyClass::SerializeToArchive1(Archive& archive)
{
    if(archive.IsStoring())
    {
        archive << my_data1;
        archive << my_data2;
        ...
    }
    else
    {
        archive >> my_data1;
        archive >> my_data2;
        ...
    }
}

MyClass::SerializeToArchive2(Archive& archive)
{
    if(archive.IsStoring())
    {
        archive << my_data3;
        archive << my_data4;
        ...
    }
    else
    {
        archive >> my_data3;
        archive >> my_data4;
        ...
    }
}
...


А если этих форматов архивов будет 10? Или 20? На каждый вариант свою функцию писать? Может быть, можно как-то покомпактнее сделать?
К тому же, такая архитектура преподлагает то, что MyClass должен знать о каждом типе архива, в который он сохраняется. По моему скромному мнению, это довольно криво.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: сохранение/загрузка
От: Cruelty  
Дата: 10.01.06 15:08
Оценка:
Ну тут надо решать: либо обьект знает обо всех архивах (т.е. форматах
сохранения) либо архив знает обо всех объектах которые в него можно
записать. В любом случае мне кажется, что логично каждый тип архива надо
наследовать от архива-родителя, чтобы код в итоге по-приличнее выглядел.
Posted via RSDN NNTP Server 2.0
Re[6]: сохранение/загрузка
От: Ilias  
Дата: 10.01.06 17:02
Оценка:
Здравствуйте, Cruelty, Вы писали:

C>Ну тут надо решать: либо обьект знает обо всех архивах (т.е. форматах

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

Типов архивов может быть много. А типов объектов, которые туда записывается — максимум штук 5.
А про наследование понятно. Но, если вы читали первоначальное письмо, вопрос был не в этом. Там было описано, что должна быть возможность сохранять в несколько разных форматов файлов и с использованием нескольких схем сохранения. Вопрос был в том, как организовать именно это.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[7]: сохранение/загрузка
От: Cruelty  
Дата: 10.01.06 17:39
Оценка:
Здравствуйте, 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 с его великолепной поддержкой версионности, наследования, сериализации смарт-поинтеров и контейнеров. И не такая уже и беда, если обьект знает как сохранять себя в каждом взятом формате.
Re[8]: сохранение/загрузка
От: Ilias  
Дата: 10.01.06 19:28
Оценка:
Здравствуйте, Cruelty, Вы писали:

C>Здравствуйте, Ilias, Вы писали:


I>> как организовать именно это.


C>Если объектов мало, добавлять новые не будут, типов архивов много и их будут постоянно добавлять/менять/удалять, то можно делать так:


Вы явно не прочитали первоначальное сообщение. Напишу в третий раз — может быть несколько форматов файлов для сохранения, а так же — может быть несколько схем сохранения.
Формат файла — это значит, что данные могут сохраняться в базу данных (sqlite для начала), xml-файл, еще какие-то форматы, и т.д.
Схема сохранения — это значит, что при использовании схемы 1 будут сохранены MyClass.data1, и MyClass.data2, а при использовании схемы 2 будут сохранены MyClass1.data3, MyClass.data4 и MyClass.data8.
Необходимо реализовать все сочетания форматов файлов и схем сохранения.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[9]: сохранение/загрузка
От: xtile  
Дата: 10.01.06 22:18
Оценка:
Здравствуйте, 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 невелико — достаточно будет в метод сериализации передавать параметр из битовых флагов.
Re[9]: сохранение/загрузка
От: Cruelty  
Дата: 10.01.06 22:44
Оценка:
Здравствуйте, 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)? Два базовых архивных класса: один ответственный за формат, а второй за схему. И их уже можно скресчивать как угодно.
Re[10]: сохранение/загрузка
От: Ilias  
Дата: 11.01.06 10:47
Оценка:
X>data1, data2, ... , dataN.
X>Если N невелико — достаточно будет в метод сериализации передавать параметр из битовых флагов.

Это пример хорошей архитектуры?? Удивительно.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[10]: сохранение/загрузка
От: Ilias  
Дата: 11.01.06 10:47
Оценка:
C>Вы кагда-нибудь слышали про множественное наследование (горяче любимые некоторыми policy)? Два базовых архивных класса: один ответственный за формат, а второй за схему. И их уже можно скресчивать как угодно.

Слышал. Но как здесь применить множественное наследование — не совсем понимаю. Если Вы сможете написать ма-а-аленький примерчик — буду очень признателен.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[11]: сохранение/загрузка
От: Cruelty  
Дата: 11.01.06 13:28
Оценка:
Здравствуйте, Ilias, Вы писали:

I> Если Вы сможете написать ма-а-аленький примерчик — буду очень признателен.


Можно так: просто и без выкрутасов. Опять повторяюсь, если типов объектов мало и они не будут добавляться/меняться.

class CStorage
{
  virtual Open() = 0;
  virtual Close() = 0;
  
  virtual Write(int value) = 0;
};

class CStorageXML : public CStorage
{
 ...
};

class CScheme
{
  virtual SaveObject(const CObType1& ob) = 0;
  virtual SaveObject(const CObType2& ob) = 0;
private:
  CStorage* m_pStorage;
};

class CScheme1 : public CScheme
{
  virtual SaveObject(const CObType1& ob)
  {
     m_pStorage->Write(ob->field1);
  }
};

void CMainClass::SerialiseAll()
{
  CStorage* pStorage = new CStorageXML(); // Class Factory?
  CScheme1 scheme;                        // Class Factory?
  scheme.SetStorage(pStorage);
  scheme.SaveObject(ob);
}
Re[12]: сохранение/загрузка
От: Ilias  
Дата: 11.01.06 15:21
Оценка:
Здравствуйте, Cruelty, Вы писали:

C>Здравствуйте, Ilias, Вы писали:


I>> Если Вы сможете написать ма-а-аленький примерчик — буду очень признателен.


C>Можно так: просто и без выкрутасов. Опять повторяюсь, если типов объектов мало и они не будут добавляться/меняться.


Не, это вполне нормально. Примерно так я и хотел сделать, но пытался выяснить нет ли других, более элегантных способов. Только где ж тут множественное наследование?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[13]: сохранение/загрузка
От: Cruelty  
Дата: 12.01.06 09:52
Оценка:
Здравствуйте, Ilias, Вы писали:

I>Здравствуйте, Cruelty, Вы писали:


C>>Здравствуйте, Ilias, Вы писали:


I>>> Если Вы сможете написать ма-а-аленький примерчик — буду очень признателен.


C>>Можно так: просто и без выкрутасов. Опять повторяюсь, если типов объектов мало и они не будут добавляться/меняться.


I>Не, это вполне нормально. Примерно так я и хотел сделать, но пытался выяснить нет ли других, более элегантных способов. Только где ж тут множественное наследование?


Извиняюсь -- был занят потому и написал такой пример по-быстрому. Вот со множественным наследованием:

class CObject1
{
public:
    int m_val;
};

class CStorage
{
public:
    virtual void Open() = 0;    

    virtual void SaveObject(const CObject1& ob) = 0;

protected:
    virtual void Write(int val) = 0;
};

class CStorageSQL : public CStorage
{
public:
    virtual void Open() {}

protected:
    virtual void Write(int val) 
    { 
        std::cout << val << std::endl; 
    }
};

class CScheme1 : public CStorage
{
public:
    virtual void SaveObject(const CObject1& ob) 
    {
        Write(ob.m_val); 
    }
};

class CArchive1SQL    : public CStorageSQL
            , public CScheme1
{
public:
    virtual void Open()
    {
        CStorageSQL::Open();
    }

    virtual void SaveObject(const CObject1& ob)
    {
        CScheme1::SaveObject(ob);
    }

private:
    virtual void Write(int val)
    {
        CStorageSQL::Write(val);
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    CObject1 ob;
    ob.m_val = 3;

    CArchive1SQL ar;
    ar.SaveObject(ob);

    return 0;
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.