Click here to Skip to main content
6,822,613 members and growing! (22,507 online)
Email Password   helpLost your password?
Development Lifecycle » Design and Architecture » Design Patterns     Intermediate License: The Code Project Open License (CPOL)

Yet Another Generic Factory Method

By jerron

An easily-applicable implementation of the design pattern Factory Method
C++ (VC6, VC7, VC7.1, VC8.0), C++/CLI, C, Dev, Design
Posted:5 May 2008
Views:6,401
Bookmarked:14 times
Unedited contribution
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
1 vote for this article.
Popularity: 0.00 Rating: 2.00 out of 5

1
1 vote, 100.0%
2

3

4

5


Introduction

Here I am introducing an easily-applicable implementation of design pattern Factory Method.

Background

Quite often we need to create objects dynamically. At design time, we don't know what exact derived class would be needed. We need to somehow create a derived class as specified (usually according to a string called "class id") at run time, and return its pointer with its base class type. We communicate with these classes only through their common interface, which is usually an abstract class.

If you are not very familiar with the term "Factory Method", a good reference can be found in the famous book Design Patterns. Or you can read the wiki page. Before I posted this article, I searched in code project and found Robert A. T. Káldy's solution Generic Class Factory, in which he also gives wonderful discussion.

The method I am introducing here differs from Robert's in that mine is easier to apply. No change in the user class or project setting is needed. As to be discussed in next section, what user needs to do before calling the creator is simply to add some files into his project, and notify the factory of all the classes to be created.

Using the code

  1. Add following 2 files into your project:
    • factory.h
    • singleton.h
  2. Register each pair of the base classes and derived classes by declaring a variable like this:
    RegisterFactory<BaseClass, DerivedClass> aDummyVariable("derivedClass_Id");
             
    In the demo project, this step is wrapped by a macro like this:
    #define IntantiateFactory(base,derived,key,suffix) \
        static RegisterFactory<base, derived>       registerFactory_ ## suffix (key)
    //in registration function
    IntantiateFactory(BaseClass, DerivedClass1,  "foo",   1); 
    IntantiateFactory(BaseClass, DerivedClass2,  "bar",   2); 
    
    //above are equivalent to
    //static RegisterFactory<BaseClass, DerivedClass1> registerFactory_1("foo");
    //static RegisterFactory<BaseClass, DerivedClass2> registerFactory_2("bar");
    
    
  3. Make sure the above registration is done before any creation function call. In the demo project, we use local static variable declaration in the first line in main function, like this:
    //initializer.h
    class Initializer{
    public:
        Initializer();
    };
    //initializer.cpp
    Initializer::Initializer(){
        IntantiateFactory(ClassFamily1, ClassFamily1Concrete1,  ID_CLASS_FAMILY_1_CONCRETE_1,   1); 
        IntantiateFactory(ClassFamily1, ClassFamily1Concrete2,  ID_CLASS_FAMILY_1_CONCRETE_2,   2); 
        IntantiateFactory(ClassFamily2, ClassFamily2Concrete1,  ID_CLASS_FAMILY_2_CONCRETE_1,   3); 
        IntantiateFactory(ClassFamily2, ClassFamily2Concrete2,  ID_CLASS_FAMILY_2_CONCRETE_2,   4); 
    } 
    
    //main.cpp  
    int main(int argc, char* argv[]){
        static Initializer initializer;  
    
        ...
    }
    
    
  4. Call the factory's creation function when you need to create the derived class, like this:
    boost::shared_ptr<baseClass> pBase=
               Factory<baseClass>::Instance().createInstance("derivedClass_Id"); 
    
    Again, we can use macro to shorten it:
    #define CreateNewBaseClass Factory<baseClass>::Instance().createInstance
    //in function where the derived class need be created
    boost::shared_ptr<baseClass> pBase=CreateNewBaseClass("derivedClass_Id"); 
    
    Please note that we do not need any knowledge about the derived class when creating them. We can include only the base class's header file here.

Points of Interest

The method introduced here can be easily extended with other dynamic creation logic. For example, instead of creating the class according to a string id, we can enable the factory to create the class directly from an istream, like this:

//current way to serialize
std::string classId;
//inStream is a given std::istream
inStream>>classId;
boost::shared_ptr<baseClass> pBase=Factory<baseClass>::Instance().createInstance(classId); 
pBase->Initialize(inStream);  //Initialized is a member method of baseClass


//extended way to serialize, above 3 step is done by factory
boost::shared_ptr<baseClass> pBase=Factory<baseClass>::Instance().createInstance(inStream); 

History

I'm working for a finance company. My job often deal with a lot of peer classes, such as different assets that generate cash flows in different rules, or different tranches allocating the cash flow to different investors in different situation. At beginning a new derived class was created though a series of if-else-if comparison. it is very error-prone, especially when a new derived class were introduced. Later a factory was created for each different base class and the creator functors are stored in a map variable. Further extracting the different factories into one generic factory resulted in the method introduced here.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

jerron


Member

Location: United States United States

Other popular Design and Architecture articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
  (Refresh) 
-- There are no messages in this forum --

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.

PermaLink | Privacy | Terms of Use
Last Updated: 5 May 2008
Editor: Chris Maunder
Copyright 2008 by jerron
Everything else Copyright © CodeProject, 1999-2010
Web22 | Advertise on the Code Project