The Abstract Factory design pattern in Python is a creational pattern that allows for the production of related objects without specifying their concrete classes, providing an abstraction level for the Factory Method.
Abstract
The Abstract Factory design pattern in Python is a powerful creational pattern that separates the process of object creation from the code that depends on the interface of an object. It adds an abstraction layer to the Factory Method and encapsulates a group of factories. The pattern is useful for working with related classes and product variants, allowing for easy extension of programs by adding new types or variants of objects without dependencies. However, it can make the code more complex and is often not used correctly.
Bullet points
The Abstract Factory design pattern is a creational pattern that allows for the production of related objects without specifying their concrete classes.
It separates the process of object creation from the code that depends on the interface of an object.
The pattern adds an abstraction layer to the Factory Method and encapsulates a group of factories.
The Abstract Factory pattern is useful for working with related classes and product variants, allowing for easy extension of programs by adding new types or variants of objects without dependencies.
However, the pattern can make the code more complex and is often not used correctly.
It is less used than other patterns but is powerful in certain cases.
You can also find all the code used through this series on GitHub.
The Abstract Factory pattern is a creational pattern allowing you to produce families of related objects without specifying the concrete class. It can be seen as an upgrade of the Factory Method because it adds an abstraction level.
Like most of the creational patterns, it separates the process of creating an object from the code that depends on the interface of an object.
It encapsulates a group of factories.
Problems the Abstract Factory can Resolve
Imagine you’re building an app to manage a pet store. For each pet you sell, you need to sell food and a collar for this specific pet.
You’ve just launched your store so for now you’re just selling dogs, so your code looks like this:
Your store is working well, and later you decide to sell collars. You have to change the code and the PetStore class, which is the client class. And after a while, you want to also sell new pets, like cats. One more time, you have to change the client class… How to avoid that?
The Abstract Factory pattern!
Solution
Let’s start with the code, and then I’ll explain it:
Now, if I want to sell other pets, I just have to create another pet factory and pass it to the PetStore. I don’t have to change this class except if I want to sell new things, such as DogFood for example.
This pattern can seem complicated, but it’s not, you just have to be methodic to use it.
First, map out a matrix of distinct product types versus variants of these products.
Then, declare abstract product interfaces for all product types (pets and collars in our case). You can then declare concrete classes implementing these interfaces.
Then, declare an abstract factory with a set of methods to create each product. In our case, it’s the PetFactory . It can create pets and collars.
You can then implement a set of concrete factories for each product variant. In our case, we have a dog variant and a cat variant.
Finally, we can just use our factory somewhere in the code to initialize our products depending on a config. In our case, it’s the PetStore class.
Do you understand? I’m sure you don’t, so let’s see another example.
We’ll build an app to manage a furniture store. We have several types of furniture, such as chairs and sofas, and for each piece of furniture two variants, a modern variant, and an old variant.
We have a matrix of 4 elements: 2 products and 2 variants.
2. We create abstract interfaces for our products, so an abstract Chair and an abstract Sofa . We can specify concrete classes representing our variants, so for each product, we have a modern class and an old class. So ModernChair , OldChair , ModernSofa , and OldSofa .
3. We create an abstract furniture factory allowing us to build chairs and sofas.
4. We create a modern furniture factory building modern variants of the furniture and an old furniture factory building old variants.
5. We create our furniture store, which is initialized with a furniture factory.
Now we can build a modern store selling modern furniture, or an old store selling old furniture! If we want, we can easily add a new furniture variant without modifying the FurnitureStore class.
Here is the code:
Applicability
I guess thanks to the examples you know when you should use the Abstract Factory pattern, but let’s summarize this here.
You should use the Abstract Factory pattern when you have to work with a lot of related classes including a lot of variants.
Usually, you don't start with an Abstract Factory. You start with a Factory Method, and when there are a lot of factories you turn these patterns into a unique Abstract Factory.
Advantages
You can easily extend your program and add new types or variants of objects without dependencies.
Products you get from the Abstract Factory are compatible without being dependent.
Disadvantages
Abstract Factory can make the code a lot more complex and is often not used correctly.
You end up having a lot of small classes instead of having everything clustered.
Final Note
As this pattern is like an evolution of the Factory Method pattern, it’s a bit more complex and harder to understand. It’s less used but it’s useful to know it because it’s a powerful pattern in some cases.
To explore the other stories of this story, click below!