Topics at a glance:
- Factory Method and abstracting the creation
- How to implement Factory method in the modern C++ way
Design patterns in C++
This chapter is the first part of a series on design patterns in C++. There are many important design patterns and so, I have decided to start a series on design patterns. I will discuss about some popular design patterns, their uses, C++ implementation, what all things we need to take care about their thread safety aspects, resource management and ownership aspect.
Creational design pattern: Factory method in C++
In this chapter, we will see factory method pattern, which is a creational design pattern, and what all we need to take care when using factories.
Factory method is simply a static class method that aids in the instantiation of objects particularly belonging to a hierarchical class system. i.e. Base class – derived class hierarchy.
This is important as factory method depends on “is a” relationship that I have mentioned in some previous chapters. i.e. any derived class instance is a base class instance. When it comes to it’s C++ implementation, we need to understand that “is a” identity works only with pointer or reference. For factory method we will work with the former i.e. pointer and not the later i.e. reference.
The example I am illustrating below, has a base-derived class system as depicted below:
Now, we need to write a shape_factory class which defines a static method which will create instances of circle or square depending upon the ‘type’ of shape we pass as parameter to this method.
Now, for fruitful use of this shape factory let us define a client that will test any shapes that it gets by simply drawing it. i.e. Client only bothers about the draw() member function defined for any shape instances. To make sure any concrete derived classes of base class shape will implement their own variant of draw member function, I have made base class’s draw member function as ‘pure virtual’. Such a base class is also known as an abstract base class in C++. Client make use of this policy. Now, let us see all this in action illustrating a factory method design pattern.
Here, everything is as I have told above, except for the use of unique_ptrs to manage ownership of the created shape instances.
NOTE: Factory method will release the ownership of created object immediately upon return and transfer it to the caller. It is caller’s responsibility to release the object instances’ memory back tofree store.
In this case client is the caller and it manage the ownership elegantly by making use of std::unique_ptr.
Now let us see the result:
Enter the radius for the new circle 1.25 Am a circle with radius 1.25 circle with radius 1.25 destroyed Enter the length for the new square 7.5 Am a square with length 7.5 square with length 7.5 destroyed Main ends here
Note that how the shapes are automatically destroyed once the client test_shapes() function returns.
NOTE: If you want shared ownership for the created objects from the factory, then use std::shared_ptr instead of std::unique_ptr.
Factory method hides the creation of objects. Usually client code will be written adhering to code to base class instance principle. Without factory, client will at least have to create specific instances of derived class objects, violating or compromising strict adherence to code to base principle. With factory method, client can fully comply to code to base class methodology.
Enjoyed the chapter? Let me know in the comments below. Thanks! 🙂