CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 5 of 5
  1. #1
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Factory pattern and linker dependencies

    Let's say I have classes A, B, and C which all derive from class Readable. I've also got a method
    Code:
    shared_ptr<Readable> ReadableFactory(istream &in);
    which reads a file and returns an object of type A, B, or C depending on the file contents (or an empty shared_ptr if the file doesn't match any of them.)

    But let's say that while A and B are similar and are used in many of the same parts of the code, C is very different, and shares only the fact that it a Readable with A and B. What's more, C has some dependencies that A and B don't have. I would thus prefer not to have code that only uses A and B depend on C.

    However, any code that uses the ReadableFactory() method will have a linker dependency on C, of course. Thus any executable using it will have all of C's dependencies even if C is irrelevant to its functionality.

    Is there some design pattern that can avoid this problem? I can't think of one, but it seems like there should be some way around it.

  2. #2
    Join Date
    May 2001
    Location
    Germany
    Posts
    1,158

    Re: Factory pattern and linker dependencies

    can't you have 2 different factory methods, one that create A and B, one that creates all three?
    Link the appropriate method and you're done.

    Although I must admit this is not a very "clean" solution. If the three classes do not have something real common, the pattern might not fit.

  3. #3
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: Factory pattern and linker dependencies

    Yeah, that occurred to me. I'm considering it.

  4. #4
    Join Date
    Nov 2006
    Posts
    1,611

    Re: Factory pattern and linker dependencies

    There are two subjects inside this question.

    I'm recognizable for pedantic and excessive posts. I'll try to be a little more compact.

    First, you would benefit from and enjoy the chapter on typelists in Alexandrescu's book "Modern C++ Design: Generic Programming and Design Patterns Applied". In that chapter (which I'm itching to stop myself from summarizing here, it's really good stuff) - he shows how you can create a list of types primarily for things like COMPLETELY generic object factories.

    Actually, a great deal of that book deals with various aspects of meta programming, and the concept of generic libraries, with solutions to the central point of your question. You're ASKING for this book - this question tells me clearly you've worked with C++ a while, and now you want to do something very generic and powerful. You'll find much of what is discussed in the book in the Loki framework, available online.

    His smart pointer class is fascinating, though when I tried it the performance was many times slower than shared_ptr - it is, however, an excellent study.

    The chapter on typelists and generic factories is a little mind bending (and in depth, with more verbage than I know I should post here). For a while it will leave you panting, wondering if you really NEED to work that hard just to make compile time functions and lists work. He intersperses this with commentary like "that's ugly, so..." and the wraps that into something simpler. By the end, it's one of those "ah, that's were this has been going" moments you're searching for.


    In a simple factory we're tempted to take a number, use some way to turn that number into an action (often a switch, could be an array of functors) - and use that action to create an object. Without using a template function, we're left with an old fashioned concept - derivation from a common base.

    Even without typelists, there are some older fashioned concepts you can group together to make this more general, but there's a small cost.

    First, make the factory a class (perhaps a non-template base, maybe with a few template functions, maybe a template derivative - design variations abound).

    Next, create an object creator. I envision this as a non-template base with a "CreateObject" virtual, and a template derivative that makes any object.

    Register these at application initialization. You're configuring the factory/reading facility at runtime (Alexandrescu shows how this can be compile time). Essentially you're making a list of the objects the factory will support.

    In short pseudo code, something like this is a start (incomplete)


    Code:
    class FactoryObjectBase
    {
     public:
    
     int id;
    
     FactoryObjectBase() : id( 0 ) {}
    
     virtual void CreateObject()=0;
    };
    
    template <typename T>
    class FactoryObject : public FactoryObjectBase
    {
     private:
     void CreateObject() { shared_ptr<T> r( new T );  }
    
     public:
    
    
    };
    
    
    
    class StreamFactory
    {
     private:
    
     vector<shared_ptr<FactoryObjectBase> > FList;
    
     public:
    
     template< typename T >
     void Register()
        {
         FList.push_back( shared_ptr<FactoryObjectBase>( new FactoryObject<T> ) );
        }
    };
    
    
    ....at application initialization, something like...
    
     StreamFactory sf; // <- subject to your storage preferences
    
     sf.Register<A>();
     sf.Register<B>();
     sf.Register<C>();
    A wide variety of configurations of this come to mind, this is merely illustrative.

    However, you can imaging that now, in a StreamFactory member:

    Code:
    FList[1]->CreateObject();

    Makes any registered object by an ID number (in this case, fashioned by the order in which they're registered). You could make that a key by a string if you wanted, using a map instead of a vector.

    Note, however, that the CreateObject I offer in FactoryObject isn't complete. It returns nothing and looses the new T....remember, this is illustrative pseudo code.

    What I imagine next in that function is a callback to an overload. Just what is up to you.

    If you still want to derive everything from Readable, then clearly this could return a shared_ptr<Readable>, but that reduces generality.

    If, instead, CreateObject were made with a policy (a second template parameter) - you direct it to the kind of storage you want. This policy might represent a functor or function overload (heck, it might not even need to be a template parameter, just supply it at creation) - directing output to wherever your storage of the new T is to go, and - it need not be derived from Readable, nor does have to a single container - you could direct toward storage based on type.

    The purpose of readable is fine, it's old style, it works. If, however, C is so unrelated to A or B that the base of readable is now a liability, shake it off. Embody the idea of Readable into a template child of a non-template base, and let that be how you IMPOSE readability upon A, B or C.


    This touches upon the general notion of reflection, one of the key ideas in streaming for various destination types. The standard streaming concept is to create a stream operator, and write the I/O code in the class to be streamed - or a non-member overload. That's fine, it works for streams, and comes to us from about 1987.

    On the other hand, if you take the concept of reflection and apply it like this, you can create a generic reflector for about the same amount of work as a stream operator, based on the "pointer to member" notion.

    The idea would then allow you to perform I/O to any destination type (SQL, 'Net, XML, text CSV, Access - whatever). You'll note that you can't expect a stream I/O function pair to help with SQL I/O, or XML I/O (unless your stream is an XML file format, and that's not always comfortable done that way).

    On the other hand, if you created a template class which embodies the notion of a pointer to member, something like (again, pseudo-code):

    Code:
    template <typename Obj>
    class MemberDataBase
    {
     private:
    
     string Name;
    
     public:
    
     MemberDataBase( const chartype *n ) : Name( n ) {}
    
     virtual void SetValue( Obj &, DataIO & )=0;
     virtual void GetValue( Obj &, DataIO & )=0;
    };
    
    
    template <typename Obj, typename Mtype>
    class MemberData : public MemberDataBase<Obj>
    {
     private:
     
     Mtype Obj::*Dptr;
    
     public:
    
     MemberData( const chartype *n, Mtype Obj::*dp ) : Dptr( dp ), MemberDataBase<Obj>( n ) {}
    
     inline Mtype & Value( Obj &o ) { return (o.*Dptr); }
    
     virtual void SetValue( Obj & o, DataIO &io )
       {  
       } 
    
     virtual void GetValue( Obj & o, DataIO &io )
       {
       }
    };
    ...and assuming some container class fashioned for this, say "Refector<T>", you'd have one function in an object to fashion a reflector....

    Code:
    class example
    {
     public:
    
     int val1;
     double val2;
     string val3;
    
     public:
    
     static void FormReflector( Reflector<example> &r )
       {
        r.AddField( "Val1", &example::val1 );
        r.AddField( "Val2", &example::val2 );
        r.AddField( "Val3", &example::val3 );
       }
    };


    ..not much more work than a stream in/stream out operator would be...you're just listing the member variables involved in I/O (you can choose to list only those you want streamed).

    However, at this point "Reflector<T>" can operate on objects independently, any object really - without requiring derivation from a base.

    All Reflector requires is a "registration" function of some kind. A small price.

    What you get is whatever you build around reflector.

    You can embody the idea of a typelist, or a type registry (you should want for Table/Column information, basically indicative of Type/MemberId required of any streaming-object factory paradigm).

    That is, Reflector will need to "know" that in this application, this is object "Example" or "Customer" - however that's indicated in your parlance. In typical simple file I/O, like streaming with factories, you number them. 1 is an A, 2 is a B, etc.

    This completes enough information that, once initialized, any form of I/O you fashion for "Reflector" is supported. You could make that XML, SQL, text, binary....anything.

    In the bargain, you get a list of members you can walk at runtime.

    How many times would you have like to be able to loop through all of the members of an object and print them out?

    Well?

    If incorporated a functor/function object in the mix, you can direct Reflector to loop through all the members that were registered for an object and call an overload by type. Doubles print doubles, ints print ints, strings print strings - on a callback model.

    Ok, I'm going overboard again. Sorry
    Last edited by JVene; August 3rd, 2009 at 01:43 PM.
    If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).

  5. #5
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: Factory pattern and linker dependencies

    I'm going to have to read that in some detail later. However, I've already got a MemberDataBase analog in my design, so I'm with you on that much at least. The registration idea certainly seems applicable, too.....

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured