Visitor design pattern (original) (raw)

Last Updated : 22 May, 2026

The Visitor Design Pattern is a behavioral design pattern that allows new operations to be added to existing classes without modifying their structure. It separates algorithms from the objects they operate on, improving flexibility and maintainability.

**Example: In an online shopping cart, different items such as books, electronics, and clothing can accept visitors to perform operations like price calculation and discount application. New features can be added without modifying the item classes.

2056957940

In the Diagram

Components

The Visitor design pattern consists of several key components that work together to enable its functionality. Here’s a breakdown of these components

Real-World Example

In an online shopping cart, different items like books, electronics, and clothing can accept visitors to perform operations such as price calculation or discount application. This allows new operations to be added without modifying the item classes.

Uses

The Visitor pattern is commonly used when multiple operations are required on a fixed set of classes.

Working

The pattern works by separating operations from the object structure using a visitor object.

concreteelementa

UML Diagram

Implementation Example

Problem statement

Assume a situation whereby you have a set of shapes like circles, squares, and triangles. You want to find the area of each given figure. One option is to add a method that calculates the area of each shape class. Yet, it breaks the open-closed principle, as modifying existing classes is mandatory whenever a new operation emerges.

There are the following steps for implementing Visitor Design Method:

Step 1: Define the Visitor interface

C++ `

class ShapeVisitor { public: void visit(Circle circle); void visit(Square square); void visit(Triangle triangle); };

Java

public interface ShapeVisitor { void visit(Circle circle); void visit(Square square); void visit(Triangle triangle); }

Python

from abc import ABC, abstractmethod

class ShapeVisitor(ABC): @abstractmethod def visit(self, circle): pass

@abstractmethod
def visit(self, square):
    pass

@abstractmethod
def visit(self, triangle):
    pass

JavaScript

class ShapeVisitor { visit(circle) {} visit(square) {} visit(triangle) {} }

`

Step 2: Define the Element interface

C++ `

#include #include

class ShapeVisitor;

class Shape { public: virtual void accept(ShapeVisitor& visitor) = 0; };

Java

public interface Shape { void accept(ShapeVisitor visitor); }

Python

from abc import ABC, abstractmethod

class ShapeVisitor: @abstractmethod def visit(self, shape): pass

class Shape(ABC): @abstractmethod def accept(self, visitor: ShapeVisitor): pass

JavaScript

// Define the Shape interface class Shape { accept(visitor) { throw new Error("Method 'accept()' must be implemented."); } }

`

Step 3: Implement Concrete Elements

C++ `

#include

class Shape { public: virtual void accept(ShapeVisitor* visitor) = 0; };

class Circle : public Shape { // Circle specific properties and methods

void accept(ShapeVisitor* visitor) override {
    visitor->visit(this);
}

};

class Square : public Shape { void accept(ShapeVisitor* visitor) override { visitor->visit(this); } };

class Triangle : public Shape { void accept(ShapeVisitor* visitor) override { visitor->visit(this); } };

Java

public class Circle implements Shape { // Circle specific properties and methods

@Override
public void accept(ShapeVisitor visitor) {
    visitor.visit(this);
}

}

class Square implements Shape { @Override public void accept(ShapeVisitor visitor) { visitor.visit(this); } }

class Triangle implements Shape { @Override public void accept(ShapeVisitor visitor) { visitor.visit(this); } }

Python

from abc import ABC, abstractmethod

class Shape(ABC): @abstractmethod def accept(self, visitor): pass

class Circle(Shape): # Circle specific properties and methods

def accept(self, visitor):
    visitor.visit(self)

class Square(Shape): def accept(self, visitor): visitor.visit(self)

class Triangle(Shape): def accept(self, visitor): visitor.visit(self)

JavaScript

class Shape { accept(visitor) { throw new Error('Method not implemented.'); } }

class Circle extends Shape { // Circle specific properties and methods

accept(visitor) {
    visitor.visit(this);
}

}

class Square extends Shape { accept(visitor) { visitor.visit(this); } }

class Triangle extends Shape { accept(visitor) { visitor.visit(this); } }

`

Step 4: Implement Concrete Visitors

C++ `

#include #include using namespace std;

class ShapeVisitor { public: virtual void visit(double radiusOfCircle) = 0; virtual void visit(double sideOfSquare) = 0; virtual void visit(double baseOfTriangle, double heightOfTriangle) = 0; };

class AreaCalculator : public ShapeVisitor { double totalArea = 0;

double radiusOfCircle = 5;
double sideOfSquare = 4;
double baseOfTriangle = 3;
double heightOfTriangle = 6;

public: void visit(double radiusOfCircle) override { // Calculate area of circle and update totalArea totalArea += M_PI * pow(radiusOfCircle, 2); }

void visit(double sideOfSquare) override {
    // Calculate area of square and update totalArea
    totalArea += pow(sideOfSquare, 2);
}

void visit(double baseOfTriangle, double heightOfTriangle) override {
    // Calculate area of triangle and update totalArea
    totalArea += (baseOfTriangle * heightOfTriangle) / 2;
}

double getTotalArea() {
    return totalArea;
}

};

Java

public class AreaCalculator implements ShapeVisitor {

double totalArea = 0;

double radiusOfCircle = 5;
double sideOfSquare = 4;
double baseOfTriangle = 3;
double heightOfTriangle = 6;

@Override
public void visit(Circle circle) {
    // Calculate area of circle and update totalArea
    totalArea += Math.PI * Math.pow(radiusOfCircle, 2);
}

@Override
public void visit(Square square) {
    // Calculate area of square and update totalArea
    totalArea += Math.pow(sideOfSquare, 2);
}

@Override
public void visit(Triangle triangle) {
    // Calculate area of triangle and update totalArea
    totalArea += (baseOfTriangle * heightOfTriangle) / 2;
}

public double getTotalArea() {
    return totalArea;
}

}

Python

from abc import ABC, abstractmethod import math

class ShapeVisitor(ABC): @abstractmethod def visit(self, shape): pass

class AreaCalculator(ShapeVisitor): def init(self): self.totalArea = 0

def visit(self, shape):
    if isinstance(shape, Circle):
        # Calculate area of circle and update totalArea
        self.totalArea += math.pi * shape.radiusOfCircle ** 2
    elif isinstance(shape, Square):
        # Calculate area of square and update totalArea
        self.totalArea += shape.sideOfSquare ** 2
    elif isinstance(shape, Triangle):
        # Calculate area of triangle and update totalArea
        self.totalArea += (shape.baseOfTriangle * shape.heightOfTriangle) / 2

def get_total_area(self):
    return self.totalArea

Example classes for Circle, Square, and Triangle

class Circle: def init(self, radiusOfCircle): self.radiusOfCircle = radiusOfCircle

class Square: def init(self, sideOfSquare): self.sideOfSquare = sideOfSquare

class Triangle: def init(self, baseOfTriangle, heightOfTriangle): self.baseOfTriangle = baseOfTriangle self.heightOfTriangle = heightOfTriangle

JavaScript

class AreaCalculator { constructor() { this.totalArea = 0; }

visit(shape) {
    if (shape instanceof Circle) {
        // Calculate area of circle and update totalArea
        this.totalArea += Math.PI * Math.pow(shape.radiusOfCircle, 2);
    } else if (shape instanceof Square) {
        // Calculate area of square and update totalArea
        this.totalArea += Math.pow(shape.sideOfSquare, 2);
    } else if (shape instanceof Triangle) {
        // Calculate area of triangle and update totalArea
        this.totalArea += (shape.baseOfTriangle * shape.heightOfTriangle) / 2;
    }
}

getTotalArea() {
    return this.totalArea;
}

}

// Example classes for Circle, Square, and Triangle class Circle { constructor(radiusOfCircle) { this.radiusOfCircle = radiusOfCircle; } }

class Square { constructor(sideOfSquare) { this.sideOfSquare = sideOfSquare; } }

class Triangle { constructor(baseOfTriangle, heightOfTriangle) { this.baseOfTriangle = baseOfTriangle; this.heightOfTriangle = heightOfTriangle; } }

`

Complete Code of Visitor Design Pattern

The overall code of the above example is

C++ `

#include #include #include

using namespace std;

// Forward Declarations class Circle; class Square; class Triangle;

// Visitor interface class ShapeVisitor { public: virtual void visit(Circle* circle) = 0; virtual void visit(Square* square) = 0; virtual void visit(Triangle* triangle) = 0; };

// Element interface class Shape { public: virtual void accept(ShapeVisitor* visitor) = 0; virtual ~Shape() {} };

// Concrete Elements class Circle : public Shape { public: void accept(ShapeVisitor* visitor) override { visitor->visit(this); } };

class Square : public Shape { public: void accept(ShapeVisitor* visitor) override { visitor->visit(this); } };

class Triangle : public Shape { public: void accept(ShapeVisitor* visitor) override { visitor->visit(this); } };

// Concrete Visitor class AreaCalculator : public ShapeVisitor { private: double totalArea = 0;

public: void visit(Circle* circle) override { double radius = 5; totalArea += M_PI * radius * radius; }

void visit(Square* square) override {
    double side = 4;
    totalArea += side * side;
}

void visit(Triangle* triangle) override {
    double base = 3;
    double height = 6;
    totalArea += (base * height) / 2;
}

double getTotalArea() {
    return totalArea;
}

};

// Main function int main() {

vector<Shape*> shapes;

shapes.push_back(new Circle());
shapes.push_back(new Square());
shapes.push_back(new Triangle());

AreaCalculator areaCalculator;

for (Shape* shape : shapes) {
    shape->accept(&areaCalculator);
}

cout << "Total area: " 
     << areaCalculator.getTotalArea() 
     << endl;

for (Shape* shape : shapes) {
    delete shape;
}

return 0;

}

Java

import java.util.ArrayList; import java.util.List;

// Visitor interface interface ShapeVisitor { void visit(Circle circle); void visit(Square square); void visit(Triangle triangle); }

// Element interface interface Shape { void accept(ShapeVisitor visitor); }

// Concrete Elements class Circle implements Shape { @Override public void accept(ShapeVisitor visitor) { visitor.visit(this); } }

class Square implements Shape { @Override public void accept(ShapeVisitor visitor) { visitor.visit(this); } }

class Triangle implements Shape { @Override public void accept(ShapeVisitor visitor) { visitor.visit(this); } }

// Concrete Visitors class AreaCalculator implements ShapeVisitor { private double totalArea = 0; double radiusOfCircle = 5; double sideOfSquare = 4; double baseOfTriangle = 3; double heightOfTriangle = 6;

@Override
public void visit(Circle circle) {
    // Calculate area of circle and update totalArea
    totalArea += Math.PI * Math.pow(radiusOfCircle, 2);
}

@Override
public void visit(Square square) {
    // Calculate area of square and update totalArea
    totalArea += Math.pow(sideOfSquare, 2);
}

@Override
public void visit(Triangle triangle) {
    // Calculate area of triangle and update totalArea
    totalArea += (baseOfTriangle * heightOfTriangle) / 2;
}

public double getTotalArea() {
    return totalArea;
}

}

// Main class public class Main { public static void main(String[] args) { List shapes = new ArrayList<>(); shapes.add(new Circle()); shapes.add(new Square()); shapes.add(new Triangle());

    AreaCalculator areaCalculator = new AreaCalculator();
    for (Shape shape : shapes) {
        shape.accept(areaCalculator);
    }

    System.out.println("Total area: " + areaCalculator.getTotalArea());
}

}

Python

from abc import ABC, abstractmethod import math

Visitor interface

class ShapeVisitor(ABC): @abstractmethod def visit(self, shape): pass

Element interface

class Shape(ABC): @abstractmethod def accept(self, visitor): pass

Concrete Elements

class Circle(Shape): def accept(self, visitor): visitor.visit(self)

class Square(Shape): def accept(self, visitor): visitor.visit(self)

class Triangle(Shape): def accept(self, visitor): visitor.visit(self)

Concrete Visitors

class AreaCalculator(ShapeVisitor): def init(self): self.totalArea = 0 self.radiusOfCircle = 5 self.sideOfSquare = 4 self.baseOfTriangle = 3 self.heightOfTriangle = 6

def visit(self, shape):
    if isinstance(shape, Circle):
        self.totalArea += math.pi * self.radiusOfCircle ** 2
    elif isinstance(shape, Square):
        self.totalArea += self.sideOfSquare ** 2
    elif isinstance(shape, Triangle):
        self.totalArea += (self.baseOfTriangle * self.heightOfTriangle) / 2

def getTotalArea(self):
    return self.totalArea

Main block

if name == 'main': shapes = [Circle(), Square(), Triangle()] areaCalculator = AreaCalculator() for shape in shapes: shape.accept(areaCalculator) print('Total area:', areaCalculator.getTotalArea())

` JavaScript ``

// Visitor interface class ShapeVisitor { visit(shape) {} }

// Element interface class Shape { accept(visitor) {} }

// Concrete Elements class Circle extends Shape { accept(visitor) { visitor.visit(this); } }

class Square extends Shape { accept(visitor) { visitor.visit(this); } }

class Triangle extends Shape { accept(visitor) { visitor.visit(this); } }

// Concrete Visitors class AreaCalculator extends ShapeVisitor { constructor() { super(); this.totalArea = 0; this.radiusOfCircle = 5; this.sideOfSquare = 4; this.baseOfTriangle = 3; this.heightOfTriangle = 6; }

visit(shape) {
    if (shape instanceof Circle) {
        this.totalArea += Math.PI * Math.pow(this.radiusOfCircle, 2);
    } else if (shape instanceof Square) {
        this.totalArea += Math.pow(this.sideOfSquare, 2);
    } else if (shape instanceof Triangle) {
        this.totalArea += (this.baseOfTriangle * this.heightOfTriangle) / 2;
    }
}

getTotalArea() {
    return this.totalArea;
}

}

// Main block const shapes = [new Circle(), new Square(), new Triangle()]; const areaCalculator = new AreaCalculator(); for (const shape of shapes) { shape.accept(areaCalculator); } console.log(Total area: ${areaCalculator.getTotalArea()});

``

Output

Total area: 103.53981633974483

Advantages

The Pros of Visitor Design Pattern are

Disadvantages

The Cons of Visitor Design Pattern are