In the previous edition of EverythingPython, I described how one version of a factory pattern could be written. You could improve upon the Factory pattern example with a small change that I will describe towards the end of this edition!
Now we come to Creational Pattern #3 (not that there’s an order) - The Abstract Factory pattern. Everywhere you look for a definition for the Abstract Factory, this is what you see -
Abstract Factory is a creational design pattern that lets you produce families of related objects without specifying their concrete classes.
What?! Why? When is this useful?
Let’s try and understand this by way of an example -
Consider the creation of a magical world with just elves and dwarves each of them possessing their respective skill sets.
Now let’s say I had to write a framework to
setup this magical world that involves the creation of one male and one female of each of these species
specify their lifespan and their skills,
Let me try and demonstrate it without and with the Abstract Factory design pattern. I came up with this example because this sort of contrived universe is perfect to use this design pattern.
💪In a brute force creation of this universe -
I create concrete classes for a male elf (ElfMale), a female elf, a male dwarf and a female dwarf.
The main point to note is that each clause per species is handled by way of the if-else clause. This makes addition of a new set of characters or more generic-ally, a new set of related objects very tedious.
💡 Now let's take a more Abstract Factory approach -
Since I have to create Magical characters with similar base properties - lifespan and skill, I can create a "Magical Character Factory" if you will that involves the creation of multiple species of beings each with these properties :
Now each magical character creation can involve the creation of a male character and a female character i.e. The MagicalCharacterFactory has two abstract methods called - create_male() and create_female()
Similar to the primary example, each Male character of a particular species can have a specific Lifespan and a Skill and likewise for the Female character of this species.
That gives us the following structure -
Now putting this all together -
What I've done here is expect that each Character Factory i.e. ElvesFactory/DwarvesFactory will create one Male and one Female of their species as evidenced by the parent (base) Interface.
Now I again set up Abstract classes for Male and Female and create concrete classes for the ElfMale, ElfFemale, DwarfMale and DwarfFemale respectively.
While this is longer by way of sheer length of code, there is no denying that this is far easier to read and to extend in the future. It also makes the client code i.e. creature_creator() extremely straightforward, all the while adhering to the Open/Close principle from the SOLID principles.
Summary :
The Abstract factory pattern is used when you know you need to create multiple related objects with varying implementations of same properties.
Feel free to mail me examples of code snippets of how you use the Abstract Factory Pattern in your codebase/ projects :)
A copy-able version of all the code in this edition can be found here - Abstract Factory Code
⚡Tip regarding Factory Pattern :
Instead of using Abstract Base Classes, if we used Protocols instead (which are themselves an instance of abc.ABCMeta, that would make the code a lot more Pythonic.