I think I have architected, designed and implemented, what might be a (bit) better Factory Pattern. Of course, I am pretty sure someone else has discovered the same variation.
Of all the patterns, very often, I was particularly bothered with “classical” aka legacy, Factory. Yes, once implemented, you can relatively easily make it create new “things”, but on the design and usability level, to me, it does not look very flexible and expandable.
On the C++ level, it requires code repetition and the use of smart pointers. In essence, these two combined, somehow do not look to me like modern C++ at all.
Classical aka “Legacy” Factory Pattern. Looking at the diagram this seems very simple and obvious. For this post, we will use the real-life use-case of the “Car Factory”. In particular to try and explain the architectural issues.
Now consider this. Using the architecture above, how would you serve contemporary customers and offer them “build your own car” service? Some online page, where customers start with some half-finished base of the car and then pick and mix a variety of engines, headlights, wheels, seats, sunroof, etc … all the way to the details like in-car sound and vision, and a such.
The architecture above is made for factories that deliver ready-made, possibly pre-built, finished cars. It is surely possible to re-organize the internals of the factory to make different variations to each model, but there is a practical limit. The more customers can pick-n-mix, the number of ever so different models raises exponentially.
The inherent flaw in this architecture is the high level of abstraction granularity. Which in turn greatly lowers the level of architecture flexibility and resilience to change.
Implementation issues
I have come to the conclusion, in each Factory pattern variation, the actual factory method, class, or whatever, is the focal point of quality issues, where one can feel the design on top of which the implementation resides.
Here is the factory method of the classical factory.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
typedef enum { model_a = 0 , model_b = 1 , model_c = 2 } car_model_tag ; typedef std::shared_ptr<IAutomobile> car_smart_pointer ; /* we must return a pointer */ car_smart_pointer obtain_new_car ( car_model_tag which_ ) { switch ( which_ ) { case model_a : return car_smart_pointer { new model_a } ; case model_b : return car_smart_pointer { new model_b } ; case model_c : return car_smart_pointer { new model_c } ; }; throw car_factory_exception{ "currently this car model is not in production" } ; } |
What is wrong with this code? Not much. It is only that this is almost C++98.
As the only modern thing, car_smart_pointer is usually implemented; with us at least since C++11, which was standard since Aug 2011 (gasp!) But there were many quality smart pointer implementations before that. (Of course, I do not mean std::smart_ptr
).
We need to use the (smart) pointer here. It is not possible to return an instance of Abstract Base Class. And this is how the automobile is implemented.
1 2 3 4 5 6 7 8 9 10 |
/* very simplified automobile interface ABC aka Abstract Base Class NOTE: C++98 */ struct IAutomobile { bool start () = 0 ; } ; |
And then we implement our two-car models by simply inheriting from this ABC.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* concrete automobile */ class sedan : public IAutomobile { // we depend on some_engine some_engine engine ; public: bool start () { return this->engine.start() ; } // the rest is the code to // implement legacy C++ // requirements } |
class cabriolet
from the diagram is almost the same. This is where we meet head-on, two things I do not like :
- Inheritance
- Code repetition
And then we invent clever design and then we “invent” coding idioms to mitigate the issues of these two. If you are by now, standing in shock or are in hot disagreement, please refer to numerous online discussions on classical factory pattern implementation issues.
I particularly like Sean Parent’s Inheritance Is The Base Class of Evil. It is about that and much more important things. Every minute is full of quality c++ and quality design decisions. Not easy to follow but worth it.
Modern Factory
The variation that I am calling “Swappable engines factory”. It is not just engines but this makes for a short title, which I think succinctly conveys the message.

Here the factory method is not the second fiddle. It is instead the key player. The product (Car in this use case) is actually assembled (put together) in the factory function. There is no such thing as a “finished car” in this architecture.
Let us discuss the factory method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// this is C++17 code namespace car_factory { enum class engine_tag : char { old = 'O', next = 'N' }; // factory inserts the engine on production line // the car is not assembled together before this point // we do not return ABC so we enjoy the value semantics inline Automobile assembly_line (engine_tag which_) { // I assume I do not need std::move in here // I could also use std::enable_if and // std::is_move_constructible // in return value type to check the // Automobile type moveability // or I could just leave it to the modern C++ compiler using namespace engine_workshop; if (engine_tag::next == which_ ) return Automobile(new inner::next{}); if (engine_tag::old == which_) return Automobile(new inner::old{}); throw std::runtime_error{ __FUNCSIG__ " Unknown engine_tag ordered?" }; } } // car factory |
This is a proper modern C++. No smart pointers needed. We are enjoying the value semantics made much easier to use with the help of a modern C++ compiler.
Copy elision on return by value is now de-facto standard in all modern compilers. C++ 17 “Guaranteed Copy Elision”, very simple explanation.
1 2 3 4 5 |
class X {} ; // X make_X () { return X{}: } |
Above is C++17 and in essence compiled into:
1 |
X x{} ; |
But beware. That is far from simple as it seems above.
This architecture will be easy to extend to offer the flexibility of composing the car, not before the customer (aka client) code requests a particular combination. For example.
1 2 3 4 5 6 7 8 |
// future extension // customer can choose engine, wheels and color // real car is returned, not the smart // pointer to the interface Automobile assembly_line ( engine_tag , wheels_tag , color_tag ) ; |
“Swappable Engine Factory” architecture users. do not have to worry about how many different models there are and will be. Implementation of it simply builds the car on the spot. Usage is rather simple.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
using namespace car_factory; auto car_1 = assembly_line( engine_tag::old ); car_1.start(); // future extension auto car_2 = assembly_line( engine_tag::next, head_lights_tag::halogen, color::burnt_orange ); car_2.start(); |
There are few more important details that are making this design possible to implement into simple and resilient modern C++. On the next page is the GitHub gist.
The Conclusion
This code is compiled and tested in Visual Studio 2017, with the latest MSVC as of 2018 June. This is not a “production code” it is more of a “proof of concept”. In case of bugs found, just wishing to comments or whatever please do not hesitate to contact me.
The eagle-eyed reader might jump on me using inheritance even in this modern factory. And native pointer, gasp! My answer: I know about Polymorphism without inheritance. It is not the focus of this post. It might be in the very near future in some future posts on this same subject.
Also in this architecture, this is also an “implementation detail”. So do we use it and will we change it, is completely hidden from the client code, which will work unchanged, in case of changes.
https://gist.github.com/DBJDBJ/c4df39f5df2188de41dce6de260a7c58
I hope you will be able to apply this rather improved factory pattern to your use cases and projects.