I am pretty sure you might have read tons of articles on Design Patterns. Even I had read a lot before actually using them in the projects that I worked on. I figured out that most of the articles that I read just explain about the patterns. They don’t clearly explain why should we use them, where to use them.
As I have used them in multiple places, I am writing this post to explain what are these design patterns, why, and where to use them. I will try my best to make you understand the concepts. Hope you like it.
Why should we use patterns at all? Sure you can do the same thing even without using any pattern. But using these patterns has already been proven working well in tons of projects and they increase the modularity, inter-component communications, and the overall maintainability of the project.
Factory, Singleton, Observer, and Builder are the four design patterns that I used most in my projects. Let’s dive in and understand them in a better way!
Most of the tech names are derived from the real world. So, what is a real-world factory? What does it do?
The factory produces one specific type of product. We process some raw material that ultimately becomes a product. The important thing is it produces multiple variants of the same type of product.
For example, let us say there is a motorbike factory called FreakyMotorBikes: FMB. By definition, the motorbikes that FMB produces, do have two wheels, a motor to run it, a handle to steer it. There are multiple variants of bikes it produces. One variant is a blue color, petrol, 2 stroke engine. Another is red color, petrol, 4 stroke engine, etc.
Another important thing about factories is, only the internal team/engineers know how and when to produce a particular variant of the motorbike. For an outsider, it is a black box and hardly matters. So the factory is solely responsible for deciding what variant to product for the available raw material.
Good, we mostly cover the principles of the factory. Now let us look at a scenario. Let us say there is a shop which fixes punctures for motorbikes. For this shop, to fix punctures, it does not matter what variant of the motorbike it is. Till the time it is a motorbike, they can fix the punctures. That means this shop can fix any produce of FMB factory. This is the exact requirement to have a factory pattern.
The above example is very similar to the motorbike factory example. Let's say we have multiple ways of logging in to our application like Facebook, Google, etc. When we login, we get some platform-specific information like google user id if it is google login, facebook user id if it is Facebook log in. We are storing this user object(mostly json) in our database. Most of our application does not care, what is the login channel except some services.
So, we just have a user factory, which by definition produces User objects with two variants: FacebookUser and GoogleUser. The raw material/input we give to UserFactory is the user json we get from the database.
The logic to decide which variant to produce is inside the factory and only the factory should have it. It ultimately returns a User(can be any variant). Now, most of the services can just treat it as a User and can get name and email. Only the services which have to do a specific operation for a particular variant can check the type as shown in code.
As the name says, this pattern is about having one and only one instance of an object throughout the application. Let me explain why do we have to do it and with what kind of objects.
Let’s say we are building a web application. We have multiple layers like users, auth, profile, etc. For each layer, we have a controller, service. Usually, services are pretty heavy in nature. They have multiple instances of other services initiated, connections to databases, pretty heavy data loaded, etc., and they don’t have any connection with consumers. That means, they can just be initiated at the initiation of the application, and just use it throughout the application.
Above is an example of a singleton. There can be multiple ways to implement it but the idea is to have one and only one instance of the UserService throughout the application. There is no possibility to have two instances of UserService in any case with the above code.
It need not be just a class, a singleton member can be a class variable or just any variable. Implementation changes as per the member, but the idea behind all is the same.
This is a pretty interesting and unique pattern. Remember each pattern has a use case and can be used in those specific use cases only. Regarding observer, as the name says, there is an entity that is observing/listening to some actions and will get triggered when those actions happen. It is a pub-sub (publisher and subscriber) modal.
To perform this, I have created a simple Observer interface, through which anyone can subscribe to one action by passing the type: BROWSE_IMG_SELECT, and the callback function as shown above. Whenever android triggers BROWSE_IMG_SELECT, the passed callback function will be called.
The concept behind this pattern is very simple: create a complex object step by step and separate the logic of building the object from the object itself.
By looking at the above example you can easily understand what this pattern is. This design can get complicated depending on what we are building. This makes the building process easy and clear.
Few things that are special about this are until we call the final method, which ultimately builds the object, the result is still being cooked. Let me give one example of it. Let’s say there is an assembly line for building a car door. The first team puts the base rack, second-team fixes all the nuts and bolts, the third team puts the mirror, and the final team paints it. Till the final team finishes it, the half-cooked car door is passed from one team to another. The same way the final number is kept in result in the above example. In a complex application, this kind of pattern makes the code clean, readable, and extendable.
You can find all the examples here https://github.com/pskd73/blog-example/blob/main/design-patterns-medium
Design patterns are better ways of structuring the code in a few specific scenarios. It makes the application work better in general, increases the extendability. I had read about these patterns a lot before but I understood them clearly when I actually used them. There are tons of articles to tell you what these patterns are, but I wanted to tell you how to identify that one should use these patterns. Hope I did it. Happy to hear from you if any. Cheers!