Design Pattern provides a guideline (best practices) to solve a problem that might occur in software development. These Design Pattern solutions were obtained by various trials and test methods used by a huge number of developers over a very long period of time. In this post, we are going to discuss the Structural Design patterns as defined by the Gang of Four (GoF).
Design Pattern solutions are independent of any programming language and platform and represent an idea to solve a common problem. If you are new to design patterns, I would highly recommend you to read the “Introduction to Design Patterns” article.
What are Structural Design Patterns?
The Structural Design Patterns help us to define relationships among various classes and objects so that when they are combined can form an organized, flexible, and connected larger structure.
There are 7 different Structural Design Patterns that help us to define solutions in various known scenarios, let us look at them in brief and try to build an understanding of what they are and when and where to use them.
Adapter Pattern
The Adapter Design Pattern helps us to build an intermediate class (called adapter) that hides the incompatibility from a class or a service (called adaptee) that a client wants to consume.
In other words, the Adapter pattern helps us to design an intermediate class (adapter) that provides an interface to the client by mapping the incompatibility (parameters, method calls, etc) to a class or a service that the client cannot consume directly.
The pattern is also known as the Wrapper pattern as it wraps the functionality of one incompatible class and invokes it internally by providing an easy to consume interface for the client.
The descriptive details about the Adapter Design Pattern along with a C# example can be found here: http://ExecuteCommands.com/adapter-design-pattern-csharp-simple-usecase/
Bridge Pattern
The Bridge Design Pattern helps us to separate an interface (or an abstract class) from its implementer class so that both entities can vary (developed) independently. The pattern provides a way to change the implementation details without the need to changes the abstraction.
Let us take a simple example to understand the pattern. We have custom business logic to process employee data, and this processed employee data will be saved as an XML on a Windows machine and as a JSON file on a UNIX machine. The saving part differs based on the operating system.
As per the Bridge Desing Pattern, we may abstract (decouple) the business processing logic from the saving logic and it will have no knowledge of how the data will be saved. The abstraction contains a reference (via composition) to the implementor. The implementor class (saving of data) details will be provided during the runtime based on the operating system and both abstraction and implementer can be developed independently.
The descriptive details about the Bridge Design Pattern along with a C# example can be found here: http://ExecuteCommands.com/bridge-design-pattern-in-csharp-simple-example/
Composite Pattern
The Composite Design Pattern allows us to have a tree-like structure forming a hierarchy and lets its client treat individual objects (leaf) and compositions of objects (nodes) with uniformity.
In simple terms, the pattern allows us to have a tree structure where every node can be expected to perform an identical (similar) task. Here in the tree structure, the leaf represents a primitive type that does not have children and is able to perform the assigned task. Whereas the nodes in the tree are a composite class whose children can be either be a composite class or a leaf node and it can also perform a similar assigned task. The intent of this pattern is that all the individual objects in a tree are treated the same way.
The descriptive details about the Composite Design Pattern along with a C# example can be found here: http://ExecuteCommands.com/composite-design-pattern-csharp-simple-example/
Decorator Pattern
The Decorator Design Pattern is a structural pattern that lets us attach additional functionalities to a class instance during runtime (dynamically), without modifying the class structure. It provides an alternative to subclassing and promotes code reusability.
The Pattern adds the functionalities to an instance by wrapping the decorator’s classes around the original object instance. Multiple decorators can add or override the functionality of the original class instance. The pattern is also known as a Wrapper Pattern and shares the name with Adapter Design Pattern.
The descriptive details about the Decorator Design Pattern along with a C# example can be found here: http://ExecuteCommands.com/decorator-design-pattern-csharp-simple-example/
Facade Pattern
A Facade Design Pattern is used to provide a single unified client-facing interface to a complex system. Here the complex system can be composed of multiple libraries, frameworks having different classes representing different functionalities.
The unified single interface is called the facade and it exposes only those limited functionalities that the client is interested in. The implementation details of the exposed functionalities are also hidden from the client. All the other functionalities of the complex system are hidden in the background, thus making it easier for the client to use the service without worrying about the whole complex system and the different functions it has to offer.
The Facade accepts all the incoming client’s requests and invokes the required function or functions from different parts of the system and returns the appropriate response to the client.
The descriptive details about the Facade Design Pattern along with a C# example can be found here: http://ExecuteCommands.com/facade-design-pattern-in-csharp-simple-example/
Flyweight Pattern
The Flyweight Design Pattern provides a way to minimize the memory footprint by managing the object state (bifurcating the constant one) so that the common constant state can be shared across similar objects.
In general, a large number of objects uses a load of memory and the pattern helps to break (or isolate) the object properties so that they can be shared across the objects. The breaking of object properties is achieved by dividing them into two types viz: Intrinsic and Extrinsic.
The Intrinsic properties are those properties that remain constant across the objects and their value can be easily shared between all objects.
The Extrinsic properties are those properties whose values vary and can be unique across the objects.
The descriptive details about the Flyweight Design Pattern along with a C# example can be found here: http://ExecuteCommands.com/flyweight-design-pattern-csharp-simple-example/
Proxy Pattern
A Proxy Design Pattern is the last Structural Design Patterns and provides a way to represent a different object and allows to access its functionality through it. Here the object representing the functionality is called the Proxy object and the object whose functionality is being represented via Proxy Object is called the “Real Subject” or “Real Object”.
The pattern adds a level of indirection by accepting requests from the client and passing the request to the Real Subject. (The request from the client can be modified by the Proxy class based on a need basis before passing it to the Real Subject).
In a simple term, A Proxy Design Pattern allows us to create a class that represents the functionality of other classes.
The descriptive details about the Proxy Design Pattern along with a C# example can be found here: http://ExecuteCommands.com/proxy-design-pattern-in-csharp-simple-example/
Conclusion
In this post, we try to learn about the Structural Design Patterns and went briefly through it various different types and what problem they try to resolve. Having knowledge about them comes really handy while developing an application of various types.
I hope you find this post helpful. Thanks for visiting. Cheers!!!
[Further Readings: Bridge Design Pattern in C# | Decorator Design Pattern in C# | Flyweight Design Pattern in C# | Composite Design Pattern in C# | Facade Design Pattern in C# | Proxy Design Pattern in C# | SQLite Studio to manage SQLite databases | Adapter Design Pattern in C# | How to use Blazor EditForm for Model Validation | How to add a new profile in Windows Terminal | How to easily Customize Global Settings in Windows Terminal | How to add Git Bash to Windows Terminal Application ]