Hi guys, today I talk about the Abstract Factory Design Pattern. This is a Creational Design Pattern and whose objective is to produce Families of related Objects.
You can see as we have two different base products: ProductA and ProductB (both interfaces) and each of them has two versions: Version1 and Version2.
In other words, we have two families of products!
Let me explain the numbers of the pic:
- Abstract or interfaces of Products: Declare different interfaces but related products which belong to a product family. For example, IProductA represents all A family.
- Concrete Products are various implementations of products, grouped by variants.
- The Abstract Factory Interface declares a set of methods for creating each of the abstract products
- Concrete Factories implement creation methods of the abstract factory.
- Although concrete factories instantiate concrete products, their creation methods must return corresponding abstract or Interface Product.
The client can work with any concrete factory/product variant but must communicate with their objects via Abstract Interfaces
Abstract Factory can be a bit confused at the beginning but I try to be clear about that. We will see 2 examples: 1 simple and another Real a bit more complex.
Simple example: Dev Restaurant 😉
We have a Restaurant called “Dev Restaurant”, that is opened only Saturday and Sunday. We have to specialities:
- Argentinian Food
- Italian Food
You can eat Argentinan Food only on Sundays and Italian Food only on Saturdays. We have just two option for each:
- Best food: Asado –> Great! Like a BBQ but Asado is better :p
- Simple food: Milanesas –> tasty!
- Best food: Lasagna
- Simple food: Pizza
This design is excellent to order quickly. We have just 2 menus.
Our system needs to do a simple operation: Get Simple foods and best foods.
This is a simple case but you can see that we have TWO FAMILIES OF FOODS: Argentinan Food and Italian Food and each family have two kinds of food: Simple and Best.
If we would have only Italian Food and Argentinian food, we need to code two Factories: ArgentinianFoodFactory and ItalianFoodFactory and each of the factories would return ArgentinianFood and ItalianFood instance respectively. For this problem, we can use the Factory Method Pattern because each of the factories returns just one type of object! But in our restaurant, each of the factories can return 2 different kinds of foods.
For these reasons, how we have families of products: The Abstract Factory is the correct way.
We applied the Abstract Factory Method to model this problem. Easy 😉
On Saturday we will use ItalianFoodFactory and on Saturday we will use ArgentinianFoodFactory.
Real Example: Access Control System 😀
When we saw the Factory Method Design Pattern, we modelled an Access Control System (You can see: Factory Method).
In that situation, we have 3 Access Controls:
At this moment, all access controls used fingerprints to validate users but today, the customer told me “Hey Fran, we will buy three kinds of Access Control, will not use just fingerprints access control. The system will need to support:
I need this feature, the next week will arrive to the office!“
Ok, big problem! But we try to think a little bit.
We have 3 different Access Control models: ZK, HP and Lg and each of them can have 3 different methods to validate users: by fingerprints, biometric or cards!
Zk, Hp & Lg devices are available in these variants: Biometric, Card & Fingerprints.
Product families and their variants:
First, we need to declare Interface for each distinct product of the product family (e.g. Zk, Hp or Lg). Then we declare all variants of products: Biometric, Card & Fingerprint.
For example, all Zk variants can implement the ZkAccessControlInterface, all Hp variants can implement HpAccessControlInterface, and so on.
Then, we need to declare the Abstract Factory Interface and it will have a list of creation methods for all products that are part of the family products (for example, CreateZk(), CreateLg() and CreateHp()). These methods must return Interfaces that represents product types. In this case the Abstract Factory must return IZkAccessControl, IHpAccessControl & ILgAccessControl.
Finally, For each variant of a product family, we create separate concrete factories that implement IAbstractFactory. A factory is a class that returns products of a particular kind: Biometric, Fingerprint & Card.
Let’s model that!
The Abstract Factory Design Pattern allows to produce families of related objects without specifying their Concrete classes.
A Factory now represents a “FAMILY” of objects that it can create.
Factory Method vs Abstract Factory
- A base class or interface defines the Creation Method
- Each Factory return only one type of object
- SubClasses implement the creation method in different ways
- Has all attributes of the Factory Method
- Concrete Factory Classes may return various objects from a Family of objects. (Not only one)
You can see the code in my github!