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
- Add the following 2 files into your project:
- 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)
IntantiateFactory(BaseClass, DerivedClass1, "foo", 1);
IntantiateFactory(BaseClass, DerivedClass2, "bar", 2);
- 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:
class Initializer{
public:
Initializer();
};
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);
}
int main(int argc, char* argv[]){
static Initializer initializer;
...
}
- 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 a macro to shorten it:
#define CreateNewBaseClass Factory<baseClass>::Instance().createInstance
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:
std::string classId;
inStream>>classId;
boost::shared_ptr<baseClass>
pBase=Factory<baseClass>::Instance().createInstance(classId);
pBase->Initialize(inStream);
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.