What are Design Patterns?
Design Patterns are solutions to common problems.
You know how there is always one guy in the group who never does his part right (?).
Well, let us say I come up with an actual solution to address this issue. It has worked for me multiple times and every time I implement my solution, that guy actually starts working!
Word spread around that my solution is able to fix this issue, so all study groups around the world start implementing it in different contexts but same issue. They all have had great success with my solution, they have implemented it as is, or with minor tweaks.
So, I have come up with a solution for a common problem and it has been proven its reusability and effectiveness on different contexts.
Design Patterns are solutions to design problems. These solutions must be reusable and must be effective in different contexts. They might need to adapt in different scenarios; however, the core solution remains the same.
This concept has been around for ages, but its introduction in the Software field was not until 1994 with the famous book “Design Patterns”.
Types of Design Patterns:
- Creational =>deals with object creation while hiding the creation logic.
- Structural => deals with class and object composition.
- Behavioral => deals with communication between objects.
The Factory Pattern falls into the “Creational” category. It allows the creation of a given subtype through a Factory class. Its main advantages are that it decouples the client from the actual object creation and encapsulates object creation.
Here, a diagram of Factory Pattern:
- IProduct: Abstract form of the object we want to create. With this Interface we define the structure of our object.
- ConcreteProduct: Actual implementation of IProduct. Created through ConcreteFactory.
- AbstractFactory: Optional component that defines the default behaviour for ConcreteFactory.
- ConcreteFactory: Used for the creation of ConcreteProduct. It can inherit from AbstractFactory.
Flow of Factory pattern:
- Client asks ConcreteFactory for ProductA.
- ConcreteFactory locates the implementation of ProductA and creates a new instance of it.
- ConcreteFactory returns ProductA.
This happens with all the products that you have.
With the implementation of this patterns noticed that:
- The class is chosen at runtime. All potential classes need to be in the same subclass hierarchy.
- Decouples client from the actual object creation.
- Encapsules object creation.
In this example let us say we have a bricks Factory with two types of bricks: “A” and “B”.
Of course, I know nothing about bricks.
These will be our IProduct, ConcreteProduct, ConcreteFactory and AbstractFactory:
- IProduct = /MyInterface/IBricks.cs
- ConcreteProduct =/Products/BrickA.cs & /Products/BrickB.cs
- AbstractFactory = /AbstractFactory/BrickFactory.cs
- ConcreteFactory = /MyFactory/Factory.cs
Main folder structure:
PS C:\Users\azureuser\source\repos\FactoryPatternBricksExampleSolution\FactoryPatternBricksExample> tree /f
First, we will create the Interface for our bricks. The common base for all of our products. This Interface will have three methods:
- GetName( return a string with the name of the product).
- GetWeightInKG( return an int with the weight of the brick).
- GetColor(return a string with the color of the brick).
Our actual products will inherit from this Interface.
Now we are going to create our two products that will inherit from “IBricks.cs”. IBricks.cs defined three abstract methods that we need to implement in our products:
- GetName() => return “A”.
- GetWeightInKG() => return 3.
- GetColor() => return “Red”.
- GetName() => return “B”.
- GetWeightInKG() => return 4.
- GetColor() => return “Blue”.
We have our Interface and our two products that inherits from this Interface.
Now, we are going to create the AbstractFactory [optional], that will define the behavior of the actual factory:
AbstractFactory contains an abstract method called “FactoryMethod” that will accept a string paramaeter. The actual Factory will implement it in order to create the products.
Let us create our actual Factory that will inherit from AbstractFactory and implement the FactoryMethod:
This method will have a switch statement and, based on the argument that it receives, it will generate one product or the other.
We have all we need.
Let us go to “Program.cs”:
In here, we are going to create our two products, but noticed both are being created through the FactoryMethod. Client never interacts directly with the actual object.
Weight: 4 Kg.
- There are two products that inherit from an Interface.
- The interface defines the based structure for the products.
- There is a ConcreteFactory that inherits from AbstractFactory.
- AbstractFactory defines the behaviour of ConcreteFactory.
- ConcreteFactory is responsible for object creation.
- ConcreteFactory sits between the client and the actual object.
- Client never interacts directly with the actual object.
- Factory Pattern is a creational pattern because it deals with object creation.
- It encapsules object creation.
- Use it when classes need to be created at runtime and all classes are in the same subclass hierarchy.