Structural Design Pattern
Learn via video courses
Overview
Structural design patterns are one of the 3 types of design patterns, which help in making a complex designed system into a simpler one, in such a way that it becomes more flexible and robust. They are highly useful for creating readable, flexible, maintainable, and layered code, especially when working with complex interdependent structures, external libraries, legacy code, or various different objects.
What is Structural Design Pattern?
Structural design patterns help in simplifying the design of the system by analyzing the relationships and similarities between the object structures, in order to integrate them into larger composite structures. They emphasize how objects can be composed into larger structures using object composition, i.e, the inclusion of objects into other objects. They have generalized the ways of assembling the classes and objects so that they can be repeatedly used in multiple scenarios as possible solutions to ensure flexibility and efficiency.
Types of Structural Design Patterns
There are 7 types of Structural Design patterns, which are described as follows:
1. Adapter Design Pattern
As the name suggests, an adapter is something that allows one entity to work with another entity that is directly not compatible. As shown in the below figure, a laptop adapter converts a relatively high-voltage electric current that is supplied by an electrical outlet to a lower-voltage electric current which is suitable for the laptop device. By allowing the electric current to be adapted to charge the laptop device, the adapter has made a larger system that comprises the laptop and the electric outlet combined by an adapter, fueled by electricity.
The Adapter design pattern allows incompatible interfaces to work in collaboration. This pattern enhances the reusability of the existing code. e.g, say we have an existing Stack class and we want this Stack class to be used as a Queue somehow. So what we can do is we can create a StackToQueueAdapter class that will internally use 2 stacks to provide a Queue's behavior.
NOTE The Adapter Pattern is also known as a Wrapper Pattern, as it wraps an existing incompatible structure along with the mediator code so that it can be utilized with an existing structure, and make a larger working system.
When to Use Adapter Design Pattern?
- Adapter Design Patterns are used when you have an existing class that needs to work in collaboration with an incompatible interface.
- It is also used to create a reusable class that can be used with incompatible classes.
2. Bridge Design Pattern
The Bridge design pattern is used for separating the abstraction from its implementation so that both of them can be varied and modified independently. It makes the design more extensible and also supports the abstraction concept of OOPs by hiding the implementation details from the clients.
Note:
- Abstraction is a technique used to hide unnecessary details from the user. It can be achieved by using Abstract Classes and Interfaces.
- Abstract class is such a class that has 2 types of functions, i.e, functions with definition and functions created along with abstract keyword which has declaration only but no definition. An abstract class cannot be used to create objects (to access it, it must be inherited from another class).
- Functions without definition are known as Abstract Methods.
- Interfaces have only abstract methods. The definition of these abstract methods is provided by the class inheriting the interface.
When to Use Bridge Design Pattern?
- Bridge patterns are used when run-time binding of the implementation is required, i.e, when you do not have prior knowledge of what implementation is to come during the runtime. e.g, say you made a Database Connection object in Java code, but since you will only get to know which database actually needs to be connected at the runtime only, so you accept the URL of the database at the runtime and bind it at that time.
- It is also used when a single implementation is needed by various objects.
3. Composite Design Pattern
The Composite design pattern is a partitioning design pattern describing that the group of objects should be treated in the same way as a single instance of the same type of object. The core philosophy behind composite patterns is that the objects can be composed into tree structures so that they can represent part-whole hierarchies.
When to Use Composite Design Pattern?
- Composite patterns are used when your code design has hierarchical structures and it requires generic functionalities across the structure.
- It is also used when your design wants to treat composite and individual objects uniformly. Composite objects are those objects which are made by grouping more than one object together.
- They are also useful in aggregating data across a hierarchy.
4. Decorator Design Pattern
The Decorator design pattern is used to allow the addition of responsibilities to objects in a dynamic fashion. This enables the object to have a flexible alternative in order to change the object's functionality without inheritance, which makes the design less flexible and more biased. Inheritance is a process in which one class acquires all the properties and behaviors of the parent class. After adding all the properties and behaviors of the parent class, it adds its own changes or responsibilities which are different from the parent class. But this all needs to be mentioned during programming itself, i.e, before compile-time only, so it makes it static and less flexible because it cannot be changed during the runtime.
When to Use Decorator Design Pattern?
- Decorator pattern is used to dynamically add additional functionalities/responsibilities.
- It is also used to add those responsibilities which can be withdrawn as well dynamically.
- When you want to avoid too much sub-classing in order to add additional responsibilities, you can use the Decorator pattern.
5. Facade Design Pattern
Facade means false and fabricated appearance, and, we already know that appearances can be deceiving, so a simple thing can be highly complex at the backend, and vice-versa. Facade design pattern helps in providing a single and simplified interface on a higher level above all other interfaces and classes so that the complexities of the system can be made hidden from the client. It helps in reducing the coupling between the clients and the complex underlying system.
When to Use Facade Design Pattern?
- Facade pattern is used when a system or the design is highly complex making it difficult to understand due to a large number of interdependent classes or source code unavailability.
- It is used to provide a single interface to a large system containing multiple classes and interfaces.
6. Flyweight Design Pattern
Flyweight design pattern promotes that a single fine-grained instance should be used for efficient sharing, thereby avoiding the cost of multiple instances that contain the same information. This pattern promotes the behavior that new objects should be created on requirement only when there is no other similar object present in order to limit memory usage.
When to Use Flyweight Design Pattern?
- Flyweight pattern can be used in a system where a large number of objects are being used that have the same use cases and information.
- It is used to lower the RAM and Storage cost of the system because redundant information structures utilize a significant RAM and Storage Cost.
7. Proxy Design Pattern
The Proxy design pattern helps you provide a placeholder or substitute object to limit the access of the original object. It allows you to create a secured mediator interface to the real resource.
When to Use Proxy Design Pattern?
- Proxy pattern is used to hide the original object so that its access can be controlled.
- This pattern is useful when the original object is present remotely and its local copy is required. This is known as a Remote Proxy.
- Proxy pattern ideology is used in creating proxy servers in organizations so that only limited websites become accessible, thereby blocking the access of irrelevant and illegal websites. All network requests go through a dedicated proxy server which first checks the requests for allowed websites and posts data to the network. If the request looks suspicious, the proxy blocks the request – else the request passes through.
- Proxy pattern is used behind the concept of lazy loading, which says that the original object is not created unless it is actually needed.
What are the Problems Solved by Structural Design Patterns?
Say, you are working in a company. In order to use some feature(s), you need to create the object(s) of some class or classes. But you realize that in order to do so the interfaces present simply do not fit unless you are willing to figure out some complex relationship between them so that you can create a required object and perform your functionality. In another scenario, say your company or team has a lot of legacy code that can't be changed but you need to create a new functionality out of it, or you notice the structures in the code are very untidy and complex for a new person to understand and make changes easily and all elements seem to be necessary. So in such cases where the existing system is too complex to be used and modified, you try to analyze the relationships between the existing structures and assemble them together.
Conclusion
- Structural Patterns help to simplify a highly complicated system by identifying the trends and relationships in the system, so that the objects can be composed to create larger structures, thereby reducing the complexity and increasing the robustness.
- Adapter pattern is used to match interfaces of different classes which are incompatible with each other.
- Bridge pattern is used to segregate an object's interface from its implementation.
- Composite pattern is a partitioning pattern that lets the client treat the individual object and its compositions uniformly.
- Decorator pattern promotes the addition of responsibilities to an object dynamically.
- Facade pattern is used to provide a single simplified interface for a complex system.
- Flyweight pattern is used to cut down the extra weight of the system by reducing the redundant objects.
- Proxy pattern is used to provide a substitute object in order to control the access to the original object.