As a software engineer, when you work for some time and get some experience with Object-Oriented Programming (OOP), you will have some realization, like:
You will find a pattern while solving similar problems in several projects, or even different places of the same project. As you gain more experience and become familiar with more solutions, it becomes easier for you, as solutions for similar problems will follow similar patterns.
You not only want to implement changes for your current task/requirement but also want to write code in such a way that it can accommodate future changes with just small to no changes in the future. So flexibility becomes important.
To achieve a good design in software engineering using Object-Oriented Programming(OOP), we rely on design patterns.
Let’s take a look at what design patterns are and what design patterns are not.
What Design Patterns are not?
- Design patterns are not full implementations of any feature or requirement.
- Solutions are not domain-specific. These patterns are general and can be implemented for any business.
- Problems related & specific to distributed systems, real-time applications, or concurrency-related issues are not handled.
- Design patterns do not represent any specific data structures or algorithms.
What are Design Patterns?
- Solutions to common/general problems while designing software.
- Reusable solution to recurring problem, that is already been tested in the real world.
- Each design pattern has a clear use case, proper implementation guidelines, and the reason for choosing that approach.
- Recognized from experience and defined by experts.
- Solutions are specifically for Object-Oriented Programming(though the same techniques can be ported and used in other programming approaches).
- Each pattern has a defined use case, a well-defined solution(with all components in detail), and consequences.
- Design patterns work as a template to solve common design patterns. The implementation guidelines are clear but not restricted. So the implementation in your use case may vary a little bit, but the approach to the solution will remain standard.
Elements of Design Pattern
Each design pattern has 4 essential elements, and these elements need to be clearly defined for a pattern. Let’s take a look at those elements:
- Name: naming a design pattern is important, as the name will give you some idea as soon as you read the name, and might also give you some idea about how the implementation is going to be. Also having a name help while discussing the design patterns, you can just mention the name to another software engineer (who has an understanding of Design Patterns) and that engineer will immediately know what you are saying. So the discussion about the approach and solutions becomes easier.
- Problem/Use-Case: the problem area or the use case needs to be clearly mentioned, for using a design pattern.
- Solution: The implementation steps are clearly defined. The relation among the parts of the implementation and how they communicate is also defined.
- Consequences: effect of the pattern implementation can be mentioned. As the effect can not always be determined fully, and it varies depending on the specific use case and implementation. So the consequences can not be fully determined while discussing design patterns.
Types of Design Patterns
We are discussing the core design patterns here. The core design patterns are divided into 3 categories, based on their working pattern.
Each category of Design Patterns contains multiple patterns.
Scope of Design Pattern
As design patterns are implemented for Object-Oriented design, so there can be 2 scopes for a design pattern:
- Class: patterns that have class scope handle relations between classes & subclasses, and these relations are fixed at compile time.
- Object: patterns that have object scope deal with the relationship between objects, and these relations can be changed at runtime.
The Following Diagram shows the categories and scopes of the design patterns.
Let’s take a look at each type and what patterns are included in each of these.
Creational Patterns
Creational patterns deal with different aspects of object creation. While creating an object, these patterns are used to wrap the instantiation process of that new object.
Here are some criteria for creation patterns:
- The different creational process does the object creation differently and is used in different use cases.
- The creation of a new object is abstracted and hidden inside the creational pattern implementation, so the client does not need to know the details while using it.
- Sometimes the creational patterns can be interchangeable. Like, in some use cases, the Abstract Factory and Prototype patterns can be used interchangeably.
- Sometimes these patterns can be complementary. Like, the Prototype pattern can use Singleton in the implementation, or the Builder can use another pattern while building elements.
Here is the list of creational patterns. Check the details and implementation in different programming languages, below.
Singleton Pattern
Ensure only one instance of a Class.
Factory Pattern
Generate objects based on selected criteria.
Abstract Factory Pattern
Factory of Factories.
Builder Pattern
Separate construction of a complex object from representation.
Prototype Pattern
Create a new object by copying/cloning an existing one.
Structural Patterns
Strctural patterns are used to compose/construct a bigger structure by using classes and objects. While building the structure, the patterns ensure flexibility and extensibility.
Here is the list of structural patterns. Check the details and implementation in different programming languages, below.
Adapter Pattern
A bridge between already existing incompatible interfaces.
Bridge Pattern
Decouple both abstraction and implementation.
Composite Pattern
Handle list of objects (compositions) of the same interface together.
Decorator Pattern
Additional responsibility to individual objects without affecting other objects.
Facade Pattern
Unified interface to make subsystems easier to use.
Flyweight Pattern
Use shared objects in multiple contexts.
Proxy Pattern
Provide a placeholder to control access to the original object.
Behavioral Patterns
Behavioral patterns deal with the communication between a group of objects or classes. By impacting communication between objects, these patterns increase the flexibility of implementation.
Class-scoped patterns use inheritance to distribute responsibility between classes.
On the other hand, Object-scoped patterns use composition instead of inheritance.
Here is the list of behavioral patterns.
Chain of Responsibility Pattern
Chain the steps of processing a command.
Command Pattern
Wrap request in an object.
Interpreter Pattern
Interpreter for language/operation syntax.
Iterator Pattern
Traverse through a list of items.
Mediator Pattern
Middleman between two objects.
Memento Pattern
Store history of state change.
Observer Pattern
Notify state change to all dependent objects.
State Pattern
Change object behavior on state change.
Strategy Pattern
Use an algorithm from a group of interchangeable algorithms.
Template Method Pattern
Let subclasses redefine certain steps of algorithm.
Visitor Pattern
Move calculation/operation from a group of Classes to a separate (visitor) class.