Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
112 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Improving our object factory

While this implementation is a good start, there are quite a few ways to improve it.  The most noticeable flaw is that we must edit the ShapeFactory class to add the necessary support for every new shape class we add to our project.  This can be both time consuming and error prone.

A better solution over hard-coding our shapes would be to dynamically 'register' shapes with the ShapeFactory class.  Listing 1 shows an object factory class that does just that.

Ok, let's inspect this code closely.  First, notice we no longer create the shape instances inside our ShapeFactory class.  Instead, we'll use function pointers to do this for us.  These function pointers are passed to the ShapeFactory via the Register method and are internally stored in a map container for quick access.  When we ask to create an instance of a class the ShapeFactory class retrieves the function pointer that is associated with the unique identifier, and executes that function to create the new instance. Pretty simple, really.  The end result is that we no longer have to edit our ShapeFactory class to add support for new shapes!

The syntax for using this new implementation has changed from the sample implementation above.  Here's an example of how to use the object factory in this new version:

Shape *CreateTriangle()
{
  return new Triangle;
}

Shape *CreateSquare()
{
  return new Square;
}
  …
ShapeFactory shape_factory;

shape_factory.Register(TRIANGLE, &CreateTriangle);
shape_factory.Register(SQUARE, &CreateSquare);

Shape *shape1 = shape_factory.Create(TRIANGLE);
Shape *shape2 = shape_factory.Create(SQUARE);

Right away you'll notice the two new functions called CreateTriangle and CreateSquare.  The sole job of CreateTriangle and CreateSquare is to simply create and return a new instance of the Triangle and Square class respectively.

The next difference is the addition of two Register calls. Since classes are no longer hard-coded in the ShapeFactory class they must now be dynamically registered via this method.  They can also be dynamically unregistered by calling the Unregister method.

A generic implementation

While we've improved our object factory there is another modification we could make that would greatly improve our design: make the object factory class generic enough to be used with any base class. This would allow us to create just one object factory class that could be used to create shapes, commands, monsters, or anything other class we may need it for.

This may seem like a tall order at first, but thanks the power of C++ templates it's not all that hard to do.  Listing 2 shows how we implement this.

There's not much to it, really.  However, you may have noticed a new templated function called CreateObject.  I figured since we were already on board the template train we might as well make our life easier and create a templated version of those functions we used in the previous implementation.

Because of the changes made above, the syntax required to use our object factory has once again changed a bit, so let's look at the new syntax closely:

ObjectFactory<Shape> shape_factory;

shape_factory.Register(TRIANGLE, &CreateObject<Shape, Triangle>); shape_factory.Register(SQUARE, &CreateObject<Shape, Square>); Shape *shape1 = shape_factory.Create(TRIANGLE); Shape *shape2 = shape_factory.Create(SQUARE);

The first thing you should notice is we now include a new template parameter when we create our object factory class instance.  This required template parameter specifies the base class our object factory will return, in this case the base Shape class.

The other syntax change is in the Register method.  Instead of hand-writing new functions for each class we register, we can now just pass the address of the templated CreateObject function instead.  The syntax is more verbose, but it saves us the time of hand-writing new functions for every class we wish to register.

The end result is that we now have an object factory class that can be used to create any type of class, and we are no longer required to write any helper classes or functions to accomplish this.  Not too shabby.





Changes, changes, and more changes

Contents
  Introduction
  Improving our object factory
  Changes, changes, and more changes

  Source code
  Printable version
  Discuss this article