Search code examples
c++design-patternstemplatesserializationdelegation

Pattern for delegation to sub-component


In the product I am working, one of very basic scenario is serialization of classes. Typically a class to be serialized calls serialization on its sub-component

e.g. if there is a class s.t. class A{B;C;D;} then A.Pack will call pack function on B,C,D.

Since there are many such classes, same pattern of code has to be duplicated over and over again. Is it possible to encapsulate this behavior in a pattern (possibly using templates and inheritance)


Solution

  • The usual way of making a template do this is to use a type list:

    #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();
    }
    

    Proper implementations of composites created from type lists give you accessors for the members and so on, but this is enough to show how they works, and prints out that it packed Fee, Fi, Fo and Fum without specifying any behaviour.