Object-Oriented Design Patterns explained using practical examples (2024)

Object-Oriented Design Patterns explained using practical examples (1)

Ronnie Schaniel

·

Follow

8 min read

·

Mar 19, 2018

--

We have a look at the 23 Gang of Four design patterns for object oriented software design. While a lot of blog posts describe them using examples around concepts like Animal, Car or Pizza, we explain each of them by a practical example. It is certainly not wrong to learn design patterns with the help of real world analogies and then be able to apply them to software design problems. But it might also help others to see how they are applied in specific software design problems.

These type of pattern support the creation of objects. Because in certain situations there are more elegant ways than using the new operator.

Abstract Factory

The Abstract Factory provides an interface for creating families of related or dependent objects without the need to specify their concrete classes. In the example below the ShapeFactory can be used to create objects based on the String shapeType. So, we do not need to specify the concrete class, but only need to pass the type string. This pattern uses inheritance to define the factories that create objects.

Factory Method

The Factory Method defines an interface for object creation but let’s the subclass decide which object to create. Referring to the code below, a Encryptor object needs an encryption algorithm. Through getEncryptionAlgorithm() it is ensured that the Encryptor actually get’s an EncryptorAlgorithm. However, each Encryptor decides which EncryptionAlgorithm is really used.

Builder

In classes that have a lot of fields you oftentimes end up with many constructors as you might need objects using different field combinations. The Builder pattern enables a more readable object creation and let’s you specify the fields that are actually needed. In the example below a DataFetcher object can be created by passing the fields that are needed in a specific case. This also makes the code more readable, while only one constructor is needed.

Prototype

The prototype pattern helps if objects are expensive to create and new objects will be similar to existing objects. It uses the clone method to duplicate existing instances to be used as a prototype for new instances.
In the example below defined access control objects are retrieved simply by using a key and a copy of the corresponding access control object is returned. This way, objects that are often needed are “created” more easily.

Singleton

A Singleton ensures that only one instance of an object is created and that this instance is globally accessible. There are not many occasions where it is acceptable to use a Singleton as it introduces global state. Logging is one meaningful example for the Singleton as the information flow happens only in one direction and therefore global state is not a big issue (in a multithread context it becomes a bit more complicated though). The private constructor in the example below ensures that the object creation only happens through getInstance() which at the same time serves as the global accessor.

These type of pattern helps to design relationships between objects.

Adapter

The Adapter Pattern works between two independent or incompatible interfaces. This is for example useful if third party code is used, but cannot be changed. In the example below, there is an application that basically sorts arrays. This is specified through the Sorter interface. The NumberSorter, a third-party library, though accepts only Lists. Therefore the SortListAdapter is created that accepts arrays, but uses the NumberSorter internally.

Bridge

The Bridge pattern is used to decouple interfaces from implementations, if there are hierarchies in interfaces as well as implementations. That way the abstraction and implementation are allowed to vary independently.
The DrawAPI and Shape subclasses in the code below are decoupled from each other and can vary independently. The DrawAPI implementation is passed to the Shape implementation at runtime.

Composite

The composite pattern allows to treat a group of objects the same way as a single object. This is for example used in tree-like object structures where a parent node’s operation influences or is dependent on child nodes. The code below organises a file folder structure as a tree. The size operation on a folder is propagated to its children which could be a file or another folder. As a client the operation only needs to be called on the parent.

Decorator

The decorator pattern allows to add functionality to an object at run-time without altering its structure. In the example below there is a simple TextField class. Through decorators additional functionality can be added at runtime for example to add scrolling or borders to the TextField. This is more flexible than deriving classes like ScrollableTextField, BorderTextField, etc.

Facade

A Facade simplifies the interface to an object or a group of objects “behind” this facade. This is for example used to harmonise interfaces of third party code or to simplify the interface for the client. In the example below SocialSharing provides an interface to multiple third party code.

Flyweight

The Flyweight pattern is applied if lots of objects from one class need to be constructed. In this case objects are shared to reduce the memory load. As shown below, Line objects in different colours are added to a pool of objects for reuse. If a new line object is requested, it is first checked whether such an object already exists and can be reused, otherwise the object is created and added to the pool for future reuse.

Proxy

In this pattern an object is a proxy to something else and can control the creation and access of it. The proxy could interface to anything, a large object in memory, file, or other resources. In the example below the RealImage contains all the data of an image, while the ProxyImage is more lightweight and in this example only uses the real image when it needs to be displayed. So, when only using the ProxyImage object, to e.g. showing the url, the memory consumption is reduced compared to the usage of the RealImage where for example every pixel needs to be accessible.

These type of pattern are concerned with the communication between objects. In most cases the dependencies between communicating objects are reduced through these patterns which leads to better software design.

Chain of Responsibility

This pattern creates a chain of receiver objects for a request. It avoids coupling the sender of a request to the receiver and gives multiple objects the chance to handle the request. Receiving objects are linked together. In the example below a chain of middleware units is constructed. The request, containing email and password, is forwarded in the chain. New elements in the chain can be easily added.

Command

In the command pattern an object is used to encapsulate all information needed to perform an action or trigger an event at a later time. As shown below, the ActionOpen defines the action as well as the object which the action is executed on. More information is not needed and another object, here menu, can execute the action.

Interpreter

The Interpreter pattern defines a representation for the grammar of a language and provides the ability to interpret sentences of that language. In the code snippet below a Plus object can interpret “operand1 + operand2” and knows what to do with that expression. More interpreters can be added without changing the structure too much. The Parser then uses interpreters to understand input.

Iterator

The Iterator is used to traverse a container of data to access the container’s elements without the need to know the underlying structure. Also, new traversal variants can be added without changing the interface of the objects or the data structure itself.
The ChannelSurfer, depicted below, can access channels in consecutive manner. The RemoteControl object does not need to care how the channels are organised. A RandomChannelSurfer, for example, can be added without much problems.

Mediator

If two or more objects need to cooperate, the Mediator pattern might be applied. Especially if the objects do not know each other, if they should not be tightly coupled, or their interaction is complex, this pattern can help.
In the example below there is some interaction needed between UI elements. This interaction is happening through the AuthenticationDialog as a Mediator. This way the interaction is not defined in one of the participating objects, but extracted into the mediator.

Memento

The Memento pattern is useful if a certain state of an object should be saved for later usage. Thereby it does not violate the encapsulation of that object’s implementation details. It can for example be used for the implementation of an undo mechanism.

Observer

In the observer pattern observer objects subscribe to an observable object to be notified every time the observable changes its data. Observers are loosely coupled and can be added and removed at run-time.
With regard to how the observer finally gets the data from the observable, there are two variants: push and pull. The code below shows the pull variant, which is more flexible as in this case the observable does not need to know how the observer wants to receive the data, but the observer can fetch the data as wished.

State

The State pattern lets an object alter its behaviour when its internal state changes. This pattern is similar to the strategy pattern, but in this case it is decided internally how the objects behaves. This is especially helpful if complex conditions define how the object should behave. New states can be added independently from existing states.

Strategy

In the context of the Strategy pattern there exist multiple variants for one algorithm where one variant is chosen to be executed at runtime.
In the example below a Compressor object can be used with one of two different algorithms defined at run-time. The method that executes the action (createArchive) then applies the chosen algorithm.

Template

The Template pattern defines a structure for sub classes in which steps of an algorithm and their order are defined. This ensures that the sub classes follow the exact same steps, providing better overview and consistency. It also allows to define default implementations for steps that can be overridden by subclasses.
As shown below all the parsers inheriting from DataParser follow the exact same steps when parse() is executed. This ensures for example that all parsers close the files and log the status.

Visitor

The Visitor pattern allows to apply one or more operation to a set of objects at run-time without having the operations tightly coupled with the object structure.
This let’s you implement double dispatch where a function call to different concrete functions is depending on the run-time type of two objects. In the example below on the one hand side there are route elements and on the other hand side visitor objects that each execute different functions on the route elements. If there are more visitors added in the future, the route element does not need to change.

These examples only provide short overviews for each design pattern and try to provide an example for each of them that shows the applicability in a software engineering context. The examples helped me to understand all the patterns, though better examples might exist. Other resources provide a more detailed description. Important is to recognise the patterns in the code and to use them when applicable and meaningful in own code.

Object-Oriented Design Patterns explained using practical examples (2024)

FAQs

What is the object oriented design pattern? ›

It can also be thought of as a template for how to solve a problem that can be used in many different situations and/or applications. Object-oriented design patterns typically show relationships and interactions between classes or objects, without specifying the final application classes or objects that are involved.

What is design patterns and give some examples? ›

A Design Pattern is identified by how it solves an object-oriented problem or issue. For example, the Bridge Pattern eradicates the dependency between the Abstraction and its Implementation by creating an object-composition link (bridge) between them.

What is the practical use of design patterns? ›

Design patterns are used with object-oriented programming paradigms which helps programmers to solve common object-oriented programming problems. When you use design patterns in your own software projects it ensures that your code is robust and bug-free.

What are the 5 principles of object-oriented design? ›

Object-Oriented Design includes these five principles:
  • S – Single Responsibility Principle (SRP)
  • O – Open-Close Principle (OCP)
  • L – Liskov Substitution Principle (LSP)
  • I – Interface Segregation Principle (ISP)
  • D – Dependency Inversion Principle (DIP)
Apr 15, 2022

What is object-oriented design in simple words? ›

Object-oriented design (OOD) is the process of creating a software system or application utilizing an object-oriented paradigm. This technique permits the creation of a software solution based on object notion. OOD is an implementation of the object-oriented programming (OOP) paradigm.

What is the best explanation of design patterns? ›

In software engineering, a design pattern is a general repeatable solution to a commonly occurring problem in software design. A design pattern isn't a finished design that can be transformed directly into code. It is a description or template for how to solve a problem that can be used in many different situations.

What are good examples of patterns? ›

Many everyday objects contain patterns. For example, a checkered tablecloth contains a repeating black and white pattern. Other examples include stripes on a bee's body, spots on a leopard, and scales on a fish.

What is a real world example of pattern? ›

Natural patterns include symmetries, trees, spirals, meanders, waves, foams, tessellations, cracks and stripes.

What is a real life example of a decorator pattern? ›

A real-life example of a decorator design pattern would be a pizza, pizza base here would be the original class, and the variety of different toppings would act as the added functionalities. The customer can add toppings (functionalities) as per their choice and the pizza base (original class) will remain intact.

Which design pattern is mostly used? ›

Factory Design Pattern

One of the most popular design patterns used by software developers is a factory method. It is a creational pattern that helps create an object without the user getting exposed to creational logic. The only problem with a factory method is it relies on the concrete component.

What is an example of problem solving with patterns? ›

For example, suppose the problem were to find the next three numbers in the series 2, 4, 6, 8. They are related in a simple way, such that 2 +2 is 4 +2 is 6 +2 is 8. In order to extend the pattern, 8 +2 is 10, +2 is 12 +2 is 14. Therefore, the next three numbers are 10, 12, and 14.

What are the five errors in using design patterns? ›

5 most common design mistakes and how to avoid them!
  • Not understand the importance of Usability.
  • Failing to understand user needs.
  • To design based on assumptions. Fail to test the design.
  • Not contribute to trends.
  • Afraid of data. Ignoring software automation.
May 24, 2020

What is an example of a pattern in the principles of design? ›

First of all, the pattern is a principle of design when certain visual design elements like lines, shapes, or colors are repeated. The most common example of a pattern is wallpaper. Secondly, we can call established design standards for certain elements a pattern.

What is the difference between design pattern and object-oriented design? ›

Its a tested design solution in a certain context. OOAD has a bigger umbrella then design patterns ,design patterns are like words in the dictionary whereas OOAD serve as alphabets ,which you use to create words. OOAD theory has been utilized to create those design patterns .

How many OOP design patterns are there? ›

As per the design pattern reference book Design Patterns - Elements of Reusable Object-Oriented Software , there are 23 design patterns which can be classified in three categories: Creational, Structural and Behavioral patterns. We'll also discuss another category of design pattern: J2EE design patterns.

What are the 3 main design principles of object-oriented programming? ›

There are three major pillars on which object-oriented programming relies: encapsulation, inheritance, and polymorphism. Phew!

Is MVC a design pattern? ›

MVC is abbreviated as Model View Controller is a design pattern created for developing applications specifically web applications.

References

Top Articles
Latest Posts
Article information

Author: Fredrick Kertzmann

Last Updated:

Views: 5928

Rating: 4.6 / 5 (46 voted)

Reviews: 85% of readers found this page helpful

Author information

Name: Fredrick Kertzmann

Birthday: 2000-04-29

Address: Apt. 203 613 Huels Gateway, Ralphtown, LA 40204

Phone: +2135150832870

Job: Regional Design Producer

Hobby: Nordic skating, Lacemaking, Mountain biking, Rowing, Gardening, Water sports, role-playing games

Introduction: My name is Fredrick Kertzmann, I am a gleaming, encouraging, inexpensive, thankful, tender, quaint, precious person who loves writing and wants to share my knowledge and understanding with you.