Stingray® Foundation : Chapter 4 Design Patterns : The Object Factory Pattern
The Object Factory Pattern
In general, it is a good programming practice to decouple the object creation and destruction processes from the actual usage of the object. On one hand, it facilitates the application of interface-oriented programming practices. Under this paradigm the objects are supposed to be manipulated only through their interfaces. However, there is one place in the program where the real type of the object needs to be known, and that is when a new instance needs to be created. Interface-based programming can greatly benefit if that unique place can be isolated from the rest of the program.
The other benefit of decoupling an object’s creation process from its usage is that it offers a greater degree of freedom in the memory allocation of the object, that is, the location in memory where the object will reside and the mechanism followed to release that memory upon destruction of the object.
The object factory pattern offers a reusable mechanism to manage the creation and release of objects. Particularly, it addresses the two main issues stated above. SFL offers an implementation of the object factory in the <Patterns\Factory.h> header file, located in your Foundation include directory. This implementation is centered around the class CObjectFactory. The declaration of this class is presented in Example 13.
Example 13 – CObjectFactory class declaration
template <typename _Base, typename _Derived,
typename _A = std::allocator<_Derived> >
class CObjectFactory:
public CObjectFactoryBase<_Base>
The template parameter _Base is the type of the object being returned by the factory. The second template parameter, _Derived, specifies the actual type of the object being created. _Base and _Derived are not necessarily the same type (although it is possible), but they are assumed to be related by inheritance: a pointer to _Derived must be implicitly convertible to a pointer to _Base.
The third template parameter specifies an allocation strategy. The default strategy used is the standard C++ allocator, which internally uses the standard C memory allocation routines. However, other strategies with more complex allocation algorithms can be plugged into the factory using this parameter.
CObjectFactoryBase<> declares the interface of the factory. The two methods declared on this interface, and implemented by the object factory are:
 
virtual _Base* CreateObject() const = 0;
virtual void DestroyObject(_Base* pObject) const = 0;
This base class is only templated by _Base, the type of the interface being returned. This allows you to give polymorphic treatment to a set of object factories that have only that element in common, but differ in the type of the actual object being instantiated or in the allocation scheme.
Creation of a new instance is achieved by calling the CreateObject() method in a CObjectFactory. The allocator functions are used to reserve the memory and initialize the object, and the functions return a pointer to the desired interface on the object.
NOTE >> Always call DestroyObject() on the same factory class that created the object. Otherwise, the deallocation process might not correspond to the allocation, and would cause unexpected errors in a program.
Example
Consider the following code.
Example 14 – Implementing factory interfaces
interface IElementBase {
<...>
};
 
class CElemImpl1: public IElementBase {
<...>
};
 
class CElemImpl2: public IElementBase {
<...>
};
 
typedef CObjectFactoryBase<IElementBase> ElementFactory;
typedef CObjectFactory<IElementBase, CElemImpl1> Impl1Factory;
typedef CObjectFactory<IElementBase, CElemImpl2> Impl2Factory;
 
IElementBase* CreateElement(ElementFactory& factory)
{
return factory.CreateObject();
}
In the sample above, an interface is declared and two implementations of that interface are provided. The creation of the objects is centralized on the CreateElement() routine, regardless of the actual implementation.
 
IElementBase* p1 = CreateElement(Impl1Factory);
IElementBase* p2 = CreateElement(Impl2Factory);
The same creation mechanism could be employed if we declare a new factory with a different allocation strategy:
Example 15 – Creating objects with an object factory
IElementBase* pShared = CreateElement(Impl1OnSharedMemoryFactory);
 
To destroy the instances, use the same factory class used to create them:
 
Impl1Factory factory1;
factory1.DestroyObject(p1);