Click here to Skip to main content
15,886,362 members
Articles / Programming Languages / C

Yet Another Generic Factory Method

Rate me:
Please Sign up or sign in to vote.
3.00/5 (2 votes)
5 May 2008CPOL2 min read 22.2K   91   17  
An easily-applicable implementation of the design pattern Factory Method

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 on CodeProject and found Robert A. T. Káldy's solution Generic Class Factory, in which he also gives a 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 is to be discussed in the next section, what user needs to do before calling the creator is simply add some files into his/her project, and notify the factory of all the classes to be created.

Using the Code

  1. Add the 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:
    C++
    RegisterFactory<BaseClass, DerivedClass> aDummyVariable("derivedClass_Id");

    In the demo project, this step is wrapped by a macro like this:

    C++
    #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 the main function, like this:
    C++
    //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:
    C++
    boost::shared_ptr<baseClass> pBase=
               Factory<baseClass>::Instance().createInstance("derivedClass_Id"); 

    Again, we can use a macro to shorten it:

    C++
    #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:

C++
//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 steps are done by factory
boost::shared_ptr<baseClass> pBase=
	Factory<baseClass>::Instance().createInstance(inStream); 

History

I'm working for a finance company. My job often deals with a lot of peer classes, such as different assets that generate cash flows in different rules, or different branches allocating the cash flow to different investors in different situation. In the beginning, a new derived class was created though a series of if-else-if comparisons. It is very error-prone, especially when a new derived class was 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)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --