Как десериализовать иерархию классов без перечислителя классов - PullRequest
2 голосов
/ 21 ноября 2010

Я использую этот подход для сериализации и десериализации иерархии классов:

 // Enumeration of classes.
 struct Type {
     enum TypeEnum { A, B }
     TypeEnum t;
     Type(TypeEnum te) : t(te) { }
     bool operator == (TypeEnum te);
     void saveToStream(Stream& stream);
     void loadFromStream(Stream& stream);
 };

 // Serializable base class.
 struct A {
     Type type;
     A() { type = Type::A; }
     // ... members
     virtual void loadFromStream(Stream& stream);
     virtual void saveToStream(Stream& stream) const;
 };

 // Serializable child class.
 struct B : public A {
     B() : A() { type = Type::B; }
     virtual void loadFromStream(Stream& stream);
     virtual void saveToStream(Stream& stream);
 };

 // Helper class.
 struct Serializer {
     static A* loadFromStream(Stream& stream)
     {
        Type t;
        t.loadFromStream(stream);
        if (t == Type::A) {
           A* a = new A;
           a->loadFromStream(stream);
           return a;
        } else if (t == Type::B) {
           A* b = new B;
           b->loadFromStream(stream);
           return b;
        } 
        throw "Unknown type";
        return 0; // surpress warning
     }
     static void saveToStream(Stream& stream, const A& a)
     {
        a.type.saveToStream(stream);
        a.saveToStream(stream);
     }
 }; 

 // Usage
 B b;
 Serializer::saveToStream(stream, b);
 B* b2 = static_cast<B*>(Serializer::loadFromStream(stream));

Этот подход довольно прост и понятен. Но я думал о том, есть ли более элегантное решение без необходимости обновлять класс Type каждый раз, когда я расширяю иерархию классов.

Есть ли у вас какие-либо советы, как это сделать без класса перечислителя Type и, возможно, без класса Serializer?

1 Ответ

2 голосов
/ 22 ноября 2010

Это кажется хорошим кандидатом на Фабричный шаблон .

По сути, он состоит из делегирования ответственности за создание экземпляра правильного типа на основе заданного идентификатора.Поиск по переполнению стека вызвал этот ответ , который дает хороший пример реализации на C ++.Обратите внимание, что все объекты, которые могут быть созданы на заводе, должны реализовывать общий интерфейс (что, по-видимому, соответствует вашему случаю).

Как только вы реализуете этот тип шаблона, вы сможете удалить if /else if каскад в Serializer::loadFromStream и просто вызов loadFromStream для объекта, созданного на фабрике.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...