Visitor Design Pattern

Learn via video courses
Topics Covered

Overview

A visitor design pattern is a behavioral design pattern used to decouple the logic/algorithm from the objects on which they operate. The logic is moved to separate classes called visitors. Each visitor is responsible for performing a specific operation.

When Will We Need the Visitor Design Patterns?

We have a list consisting of many shapes (square, circle, rectangle, etc.), and we want to calculate values like area, perimeter of those shapes. The straightforward way is to have area() and perimeter() methods in the respective shape classes. But in this method, we are tightly coupling the algorithm (calculate area, perimeter, etc.) from the objects (square, circle, rectangle, etc.) on which they operate.

With the visitor design patterns, we can remove this tight coupling by separating the algorithms and the objects on which they operate. In the future, if any new algorithms are to be added to the objects, they can be added separately without touching the underlying objects. This leverages the Open/Closed principle (i.e.) classes should be open for extension but closed for modification.

Visitor Design Patterns

How Do Visitor Design Patterns Work?

We will take the problem mentioned above as an example. We will create a Shape interface and create concrete shape classes such as Square, Circle, and Rectangle. We will then implement the visitor design pattern by defining separate visitor concrete classes to calculate area and perimeter and apply them to the shape objects.

Structure

Visitor design patterns have a few core participants such as Visitor, Concrete Visitors, Element, Concrete Elements, etc.

Structure of Visitor Design Pattern

Visitor The visitor interface declares a set of visit() methods that take concrete elements as arguments.
E.g.: ShapeVisitor

Concrete Visitor Concrete Visitors implement the Visitor interface and override the visit() method with respective operations.
Eg: AreaVisitor, PerimeterVisitor.

Element Element interface declares an accept() method that takes the Visitor interface as an argument.
E.g.: Shape

Concrete Element Concrete Elements implement the Element interface and override the accept() method. The only purpose of the accept() method is to call the visit() method of the concrete visitor that it takes as the argument.
E.g.: Circle, Square, Rectangle.

Client Client is responsible for creating the concrete visitor instances and passing them to the accept() method of the concrete element instances.

Implementation

  1. The first step is to create the Shape interface with a single method, accept().
  2. Create the concrete element classes Square, Circle, and Square that implement the Shape interface.
  3. Create the ShapeVisitor interface with overloaded visit() methods, each accepting a concrete shape class.
  4. Update the accept() method of the Shape interface to accept the ShapeVisitor interface as an argument.
  5. Create the concrete visitor classes AreaVisitor and PerimeterVisitor that implement the ShapeVisitor interface and override all its overloaded visit() methods.
  6. Finally, create the Client class responsible for creating concrete elements and concrete visitor objects.

Pseudocode

Pseudocode of Visitor Design Pattern

Element

We create the Shape interface with a single method, accept(), that accepts ShapeVisitor as an argument. We will add this code and create a ShapeVisitor interface later.

Pseudocode

Java

Python

C++

Concrete Elements

We create concrete elements Circle, Square, and Rectangle that implements the Shape interface and override the accept() method.

Pseudocode

Java

Python

C++

Visitor

We create the ShapeVisitor interface with visit() methods declared for all the shape classes Square, Circle, and Rectangle.

Pseudocode

Java

Python

C++

Concrete Visitors

We create concrete visitors AreaVisitor and PerimeterVisitor that implements the Visitor interface and overrides all of its visit() methods.

Pseudocode

Java

Python

C++

Client

Finally, we create the Client class responsible for creating the concrete visitor objects and passing them to the concrete element's accept() method.

Pseudocode

Java

Python

C++

Output

Explanation We created a list of Shape objects that contains the shapes Square, Circle, and Rectangle. We also created the AreaVisitor and PerimeterVisitor instances. The shape objects are iterated, and each of their accept() methods is called with the AreaVisitor and PerimeterVisitor. Finally, the result is fetched by calling the respective visitors' get() method.

Pros and Cons of Visitor Design Pattern

Pros

  1. Adding a new operation to all the Elements can be done easily by adding a new Concrete Visitor that implements the Visitor interface. The Element classes are left untouched.
  2. Visitors can maintain the state when they visit each element and are encapsulated. The data can be retrieved through a separate public method (get()) provided by the visitors.

Cons

  1. A new class is added for every new operation performed on the Elements.
  2. All the visitor classes have to be changed for every new element introduced.

Difference between Visitor Pattern and Strategy Pattern

Visitor Design PatternStrategy Design Pattern
Visitor design pattern is used when we want to add operations to a family of classes without touching them directlyStrategy design pattern is used when there are multiple algorithms for the same task, and we want to pick the best one at runtime
Visitor design pattern helps on maintaining multiple operations for a set of classesStrategy design pattern helps on maintaining several algorithms for a single operation
Example: AreaVisitor and PerimeterVisitor are used for different functionalitiesExample: CardStrategy and NetBankingStrategy are used for same functionality (i.e) debit money from account

FAQs

Q: When Should the Visitor Design Pattern Be Used?

A: Visitor design pattern should be used when performing several operations on a set of objects, and we don't want to have logic in those objects.

Example We want to compute area and perimeter on shape objects, and we don't want to have the logic in the shape objects. We can leverage visitor design pattern my adding the logic in separate visitor classes.

Q: What is the Use of Visit and Accept Methods in the Visitor Design Pattern?

A: The visit and accept methods in the visitor design pattern are used to apply logic to the elements. The accept() method is added in the Concrete Element classes, and it accepts the Visitor as an argument. The visit() method is present in the Concrete Visitor classes, containing the operational logic. The visit() method will be called inside the accept() method.