![]() |
Development Lifecycle »
Design and Architecture »
Design Patterns
Intermediate
License: The Code Project Open License (CPOL)
Yet Another Generic Factory MethodBy jerronAn easily-applicable implementation of the design pattern Factory Method |
C++ (VC6, VC7, VC7.1, VC8.0), C++/CLI, C, Dev, Design
|
||||||||
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
Here I am introducing an easily-applicable implementation of design pattern Factory Method.
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.
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");
//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;
...
}
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.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);
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.
General
News
Question
Answer
Joke
Rant
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 |