A Design Pattern is a solution to a repeatable problem that occurs most commonly in software design. In other words, a 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. Design Pattern solutions are independent of any programming language and platform and represent an idea to solve a common problem and are not code implementation.
Gang of Four (GoF) – Design Patterns
Introduction to Design Patterns will be incomplete if the article does not talk about the famous “Gang of Four” (GoF), Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. These four gentlemen published the book titled “Design Patterns – Elements of Reusable Object-Oriented Software” in the year 1994, which introduced the concept of Design Patterns into the software world.
The book got its nickname as “GoF Design Patterns” because of its four authors and is one of the most popular books in the software world. The design patterns described in this post are will talk about the patterns as described by the GoF and are related to object-oriented programming. (Design Pattern on Wiki)
Benefits of Design Patterns
The design patterns have evolved over a long period of time and have contributed to architecting and constructing flexible and maintainable software applications. This is achieved by using the proven patterns across different types of applications that not only helped in reducing the complexity of the design process but also helped in reusability by not reinventing the wheel. Developing an application using design patterns provides many benefits like:
- Design patterns are well documented and help to understand questions like what, when and how, helping the developer to correctly implement the pattern.
- Design patterns help you to solve common design problems through a proven approach
- Promotes reuse of developed code.
- Helps in developing complex software architecture with ease by using already proven architectures.
- Reduces overall application development time.
- It allows the development team to communicate with defined standard nomenclature, making the developer understand architectural design and implementation.
- Increases consistency between applications.
Drawbacks of Design Patterns
The design patterns provide a solution to common software problems and the above-mentioned benefits but it does have its own drawbacks that should be taken into account. Few of them are listed below:
- The architecture of an existing application needs to be modified if the implementation of design patterns are implemented in later stages.
- The design patterns tend to confuse the new developers in understanding the implemented patterns.
- There are huge numbers of patterns available, knowing and correct implementation requires a learning curve.
Classification of Design Patterns
Based on the solution a design pattern provides, they are classified into three major categories:
These patterns are concern with the way in which an instance of an object is created and helps in reducing the complexities and instability by creating the object instances only on a need basis. The creational pattern reduces the decoupling created due to the direct use of a “new” operator by the object to instantiate its dependencies. There are many patterns that fall into this category, here are a few that are used most commonly.
- Singleton: The Singleton Design Pattern ensures that there is one and only one instance of a class that exists throughout the application runtime. The Singleton class also provides a global access point and so that it can return the only instance it created and serve the same to whoever wants to access it.
- Factory Method: The Factory Method pattern provides an interface in the base class for creating an object and lets the derived (subclass) class decide which class object to instantiate. The pattern helps to defer the instantiation to the derived class.
- Abstract Factory: The Abstract Factory pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. The Abstract Factory has the responsibility for providing the creation service for the entire family of objects.
- Builder Design: is a creational design pattern that is used to build an object in a step by step manner and assembling the output of each step to get the final object instance. The pattern is commonly used to build complex objects.
- Prototype Design: is used to create a clone or a duplicate of an existing object in order to avoid the expensive operation of new object creation. The pattern is used when object creation is an expensive affair (time-consuming, memory-intensive, or complex to create)
The Structural pattern provides the blueprint about how to organized different classes and objects to form the larger application structure in a flexible and extensible way. This ensures that if any part of the application changes it does not disrupt the entire application structure.
In other words, Structural patterns are concerned about providing solutions and proven standards regarding the object composition and structure and they rely upon the interface and inheritance concepts allowing multiple classes to work together as a unit. Again, there are many patterns that fall into this category, but we will look into the basic overview of three patterns.
- Adapter Pattern: The adapter pattern as the name suggests adapts one interface to another. The pattern helps to bridge the gap between two unrelated or sometimes completely different interfaces. Such as wrapping legacy working set for newer consumers.
- Facade Pattern: The Facade pattern provides a simple and unified interface to a subsystem in use. The pattern hides the inner complexities of the subsystem and provides a very simple interface to use only the required services from the subsystem without worrying about what all it offers.
- Decorator Pattern: The Decorator pattern help to modify the instance of an object during runtime, the modification is achieved by wrapping up the instance with a decorator class and apply the required modifications. The best part of these patterns it only affects the instance of an object on which the decorator is applied and has no effects on the similar other instance of the class without a decorator.
- 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.
- Composite Design: 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.
- Flyweight Design: 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.
- 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 Behavioral patterns are concerned with providing solutions regarding the object interactions and help to design them in a way that these objects are loosely coupled and can be tested independently. Like the other patterns classification, there are many patterns that fall into these categories, but we going to see the basic overview of three such patterns.
- Command Pattern: The Command pattern facilitates wrapping of a request object as command and passing it to an Invoker object. This Invoker object, in turn, finds the appropriate handler object that can handle the request, on finding the same, the Invoker passes this command to the handler object which in turn executes the action as per the command received.
- Chain of Responsibility Pattern: The patterns let you pass a request along a chain of handler objects, On receiving the request the handler object can choose to perform the action or can choose to send the request to the next handler in the chain.
- Observer Pattern: The Observer pattern lets you notify all the objects that have subscribed to an event occurrence of an object. In other words, whenever an event occurs in an object all the dependent objects will get notified about the same. The Observer pattern defines the One-to-Many relationship.
Please note that there are more than 20+ design patterns that fall into the Creational, Structural and Behavioural categories and all of them are not mentioned here, they will be discussed in their separate dedicated post.
I hope that post gives you an idea about Design Patterns and you found this post helpful. Thanks for visiting, Cheers!!!
[ Further reading: Introduction to Machine Learning | Basic Machine Learning Terminologies | Machine Learning Framework to Learn in 2020 | Introduction to Blazor Server Application | Blazor Server Application Project Structure | Introduction to NET Core WPF | How to create WPF application using dotnet-cli | Creational Design Patterns | Flyweight Design Pattern in C# | How to add Git Bash to Windows Terminal Application | How to customize Windows Terminal Application | How to customize Windows Terminal Key Bindings | How to use Blazor EditForm for Model Validation using C# | How to publish a Blazor Server Application to IIS ]