Learn how to implement structural design patterns for reusability and maintainability in modern development. In this blog, we code examples of Facade and Decorator patterns to optimize your software design.
Design patterns provide optimized and reusable solutions for frequently encountered programming challenges. They are not ready-made classes or libraries that can be plugged into a system, but rather blueprints that need to be adapted to suit specific requirements. These patterns can be implemented in different programming languages, depending on their capabilities, and they are not limited to one language. It's essential to keep in mind that while the wrong application of a design pattern can have undesirable effects when used appropriately, it can significantly enhance the performance of a system.
Benefits of design patterns:
It is important to remember that design patterns are not a magic cure that will solve all problems; rather, they are a tool to be used as part of your arsenal; they should be chosen carefully depending on the situation and adapted to the specific requirements of a project.
So in one word, design patterns provide us with reusability, maintainability, flexibility, and scalability.
There are more than 23 patterns defined under the Gang of Four design pattern. It's recommended that you learn it through practice. We'll go over commonly used design patterns in depth and learn some examples of how they can be used.
Let us cover Structural design patterns.
Patterns that deal with object composition and object relationships are known as structural design patterns. These patterns all revolve around connecting objects to form larger structures. Some of the most well-known structural designs
The facade pattern is a design pattern that creates a simpler interface for a complex system. It is often used to hide the complexity of a system behind a single, easy-to-use interface.
Suppose you have one complex system that has different subsystems underneath. so we can have one simplified interface to hide those implementations and expose only one interface.
Let’s see this with an example,
Let's create a complex system with three subsystems: CreateUser, SendUserMessage, and NotifyAdmin, as well as a function that instantiates all of these subsystems.
Now, let us write receiver functions with the name "Call" that call the logic of each subsystem, as well as a single struct that encloses the object to the complex struct.
Now that we've defined the subsystem and wrapped the complex system in a facade, let's write a single function that calls all of these methods. The scenario is that there is a system that creates a user when it calls createUser. Send a message to the user, then notify the admin that the user has been created. Now we'll write a single function that calls all of these methods, encapsulating all of the underlying implementations as well as the driver function for the code in the main block.
The decorator pattern is a structural design pattern that allows behaviour to be added statically or dynamically to an individual object without affecting the behaviour of other objects in the same class.
The decorator pattern is used to add new behaviour to an existing class by enclosing it in a decorator class. The decorator class is intended to implement the same interface as the original class, allowing it to be used as a drop-in replacement.
Let's look at a real-world coding example: I was working on a project where it was necessary to log metrics to new relics, so each time the function is called, I need to pass the context and metrics to new relics, so at the end of each function I was required to call the new relic APIs to log metrics, but the issue is that the interface has multiple implementations, resulting in redundant code for each function that implements the interface.
Let’s take an interface that has Method1() in it, and there will be two implementations for the interface with the same method.
Now, we can write decorator for two services and add logic on top of it
And finally, the main method is to call the decorator.
So before calling the actual method, we have built up a pile of logic that is common across the objects that implement the IService method.
Finally, structural design patterns are an effective tool for software developers to use when designing and building systems. These patterns provide a common language as well as a set of best practices for organizing and structuring code to make it more reusable, maintainable, and extendable. The Adapter, Bridge, Composite, Decorator, and Facade patterns are among the most popular structural patterns. Each of these patterns addresses a specific set of challenges and can be used to improve the overall design of a system in a variety of situations. Developers can create systems that are more robust, scalable, and easy to understand and maintain by understanding and applying these patterns.