在我正在工作的产品中,非常基本的情况之一是序列化类。通常是在其子组件上进行序列化调用的类

例如,如果有ST类A {B; C; D;}类,则A.pack将在B,C,D上调用Pack函数。

由于有许多这样的类,因此必须一遍又一遍地重复相同的代码模式。是否可以将此行为封装在模式中(可能使用模板和继承)

有帮助吗?

解决方案

制作模板的通常方法是使用类型列表:

#include <iostream>

// typelist definition
struct Empty {};

template < typename H, typename T = Empty >
struct Cons {
    typedef H head;
    typedef T tail;
};

// interfaces all items support
class IPack
{
public:
    virtual void Pack() = 0;
};

// some packable items
class Fee : public IPack
{
public:
    virtual void Pack() {
        std::cout << "Packed Fee\n";
    }
};

class Fi : public IPack
{
public:
    virtual void Pack() {
        std::cout << "Packed Fi\n";
    }
};

class Fo : public IPack
{
public:
    virtual void Pack() {
        std::cout << "Packed Fo\n";
    }
};

class Fum : public IPack
{
public:
    virtual void Pack() {
        std::cout << "Packed Fum\n";
    }
};

// these two templates create a composite IPack from a list 
// of the types of its parts
template <typename Types>
class PackList : public PackList<typename Types::tail>
{
protected:
    typedef typename Types::head Item;
    Item item;

public:
    virtual void Pack() {
        item.Pack();
        PackList<typename Types::tail>::Pack();
    }
};

template <>
class PackList<Empty> : public IPack
{
public:
    virtual void Pack() {}
};

// FeeFiFoFum is a composite of four items
class FeeFiFoFum : public PackList<Cons<Fee,Cons<Fi,Cons<Fo,Cons<Fum> > > > >
{
};

// create a FeeFiFoFum and call pack on it, which calls pack on its parts
int main ()
{
    FeeFiFoFum giant;

    giant.Pack();
}

根据类型列表创建的合成材料的正确实现为您提供了成员的访问者,但这足以显示它们的工作原理,并打印出它包装的费用,FI,FO和FUM而无需指定任何行为。

其他提示

有助于实现这一目标的一种可能的设计是使用 复合图案. 。您的组件(从Wikipedia图纸中借用)是 可包装, ,将实施 模板方法 可以做类似的事情的pack():

GetChildren();
    for each child:
        child.Pack()
PackImpl();

Packimpl()是纯虚拟方法 可包装, ,以及所有继承的班级适当地实现它。 getChildren()将返回一个STL容器(可能为空)进行迭代。它可以在 可包装, ,以及一个私人会员集合来存储子对象。基本上,您然后继承了所有类 可包装, ,实现PackImpl(),您就完成了。

请注意,如果您的继承层次结构取决于孩子直接是成员,这将导致问题。如果您从聚合方面解决了问题,则应该很好地工作。

访客模式可能会有所帮助。

http://en.wikipedia.org/wiki/visitor_pattern

这样做的想法是将遍历逻辑(穿过对象踏上)与每个对象的处理。在这种情况下,每个对象逻辑正在序列化(编码)一个对象(当然是必不可少的对象)。使用普通的OOP技术,这应该相当简单且最小化。

实施遍历和访客模式特定的代码很烦人,但这主要是样板,应该是一次性的。

一位评论者写道:

如果您的意思是“有什么方法可以编写一个模板以自动调用我每个成员变量的方法?”,那么答案是否...

我的(有点邪恶的)对抗 是的,如果该方法是破坏者...

#include <iostream>
using namespace std;

bool Enable = false;

template <typename T>
class DS : public T {
public:
    ~DS() {
        if (Enable) T::Serialize();
    }
};

class A {
protected:
    void Serialize() { cout << "A" << endl; }
};

class B {
protected:
    void Serialize() { cout << "B" << endl; }
};

typedef DS<A> DSA;
typedef DS<B> DSB;

class C {
protected:
    void Serialize() { cout << "C" << endl; }
private:
    DSA a;
    DSB b;
};

typedef DS<C> DSC;

int
main()
{
    DSC c;
    {
        DSC c_copy = c;
        Enable = true;
    }
    Enable = false;
}

输出是反向顺序的,因此,要重建对象,您必须解析序列化数据并将每个已完成的对象推在堆栈上。然后,复合物体会知道有多少个孩子从堆栈中弹出。或者,当然,序列化可以进入中间结构。

另一个有趣的想法是使用此黑客 一次 在启动(创建和销毁一个特殊对象)上,来自击路仪的回调将创建描述原始对象的数据结构。

我还注意到,隐性复制构造函数有可能遭受类似的滥用,并且可能会以远期顺序...

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top