Open In App

Visitor Design Pattern in Java

Last Updated : 03 May, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

The Visitor Design Pattern is a behavioral design pattern that allows you to separate algorithms or operations from the objects on which they operate. It enables you to add new operations to objects without modifying their structure.

Visitor-Design-Pattern--(1)

What is the Visitor Design Pattern?

The Visitor Design Pattern is a behavioral design pattern that enables the separation of algorithms or operations from the objects they operate on. It allows you to define new operations on a collection of objects without modifying their classes directly. In essence, the Visitor pattern facilitates adding new behaviors or operations to an object structure by encapsulating them in separate visitor objects, thereby promoting extensibility and flexibility in the design.

Real-Life Example of the Visitor Design Pattern

Imagine you own a zoo with different types of animals: lions, monkeys, and elephants. Now, you want to perform various tasks on these animals, such as feeding, cleaning, and monitoring their health.

Instead of modifying each animal’s class to accommodate these tasks, you can implement the Visitor pattern:

  • The zookeepers represent the visitors.
  • The animals represent the elements.
  • Each type of animal (lion, monkey, elephant) has specific tasks associated with it.

Here’s how it works:

  • Each animal has an accept method that allows a zookeeper to visit it.
  • When a zookeeper visits an animal, the animal invokes the appropriate method on the zookeeper, depending on its type.
  • For example, if a zookeeper wants to feed a lion, the lion would invoke the feed method on the zookeeper.
  • Similarly, if a zookeeper wants to clean an elephant enclosure, the elephant would invoke the clean method on the zookeeper.

By using the Visitor pattern in this scenario, you can add new types of tasks or visitors to the zoo without changing the existing animal classes. This makes it easier to manage and extend the zoo’s functionality over time.

Key Components in the Visitor Design Pattern

1. Visitor Interface

  • The Visitor interface sets the visit methods, and every method corresponds to some kind of element in the object structure.
  • Such techniques take various methods to call specific types of elements as the arguments.
  • The interface definition is what the Visitor Method uses to separate operations (caused by concrete visitors) from the elements (defined by concrete elements), improving the agility and extensibility of the system.

2. Element Interface

  • The Element interface has a declared accept method with a parameter of a visitor object.
  • It is this technique that helps the visitor to execute the method on the element.
  • Consequently, each concrete element class has a defined method to call the suitable visit procedure of the visitor. It enables the Visitor Method to dynamically run the visit methods considered with the type of element found.

3. Concrete Visitors

  • Concrete visitors are the implementations of visitor interfaces in concrete form. Every concretitude suggests one single operation to be performed on the subject matter.
  • Hence, after the visit technique has been implemented, visitors are the ones who will then define the behavior for each element type.
  • Concrete Visitors like algorithms or behavior encapsulating the elements, putting off crosscutting concerns and maintainability.

4. Concrete Element

  • Concrete elements implement concrete classes of the interface element. Concrete classes correspond to each concrete element class in the element structure.
  • Concrete Elements implements an accept method that can invoke the similar corresponding visit method of the visitor.
  • This provides the visitor a chance to access the internal state and to work with the element. Concrete aspects of the model cover the data and behavior characteristics unique to each of the elements involved.

UML Class Diagram of the Visitor Design Pattern

Class-Diagram-of-Visitor-Design-Pattern--(1)

Example of the Visitor Design Pattern

Below is the problem statement to understand visitor design pattern:

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:

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

Step 2: Define the Element interface:

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

Step 3: Implement Concrete Elements:

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);
    }
}

Step 4: Implement Concrete Visitors:

Java
public class AreaCalculator implements ShapeVisitor {
    double totalArea = 0;

    @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;
    }
}

Complete Code of Visitor Design Pattern

Below is the overall code of the above example:

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<Shape> 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());
    }
}
Output
Total area: 103.53981

Use Cases of the Visitor Design Pattern

Below are the use cases of visitor design pattern:

  • Document Processing:
    • In document processing applications you regularly operate with complicated structures of objects representing different types of elements like paragraphs, headings, lists, images, etc.
    • The Visitor Method can be applied to these objects to perform various operations without their classes.
    • For instance, you could determine an interface for visitors consisting of techniques for creating HTML or PDF representations of document elements.
    • User format whatsoever is sure to encompass a particular action for each element type thus cleanly separating the concerns and keeping the processes modular in the documents processing systems.
  • Compiler Design:
    • In the Visitor Method of compiler design, traversing through the abstract syntax trees (ASTs) and performing several compiler tasks like type checking, optimization, and code generation are done.
    • Every node in the AST demonstrates an expression, statement, or function, and the Visitor Method helps you act on these nodes by defining different operations without modifying the classes.
    • For example, you could define a visitor interface with methods for performing type-checking on expressions and statements, and concrete implementations sourcing specific type-checking logic for each node type.
  • GUI Component Frameworks:
    • In graphical user interface (GUI) component frameworks, the Visitor Method can perform various operations on the components of the GUI hierarchy like rendering, event handling, or layout.
    • Every element of the GUI hierarchy signifies a different type of visual component (for instance, the buttons, panels, and text fields), so the Visitor Method enables one to specify different operations on these components without needing to change their classes. For example, there could be interfaces for the visitor that can be used to render components and concrete visitors which will include concrete rendering logic for each component type.

Advantages of the Visitor Design Pattern

Below are the advantages of visitor design pattern:

  • Separation of Concerns:
    • Visitor Pattern that creates cleanness of responsibilities by structuring the algorithm or operation independent of the object that this operation acts on.
    • This separation lets you decouple the pure logic of an operation in a class and gives you concrete visitors as concrete implementations.
    • This makes the code so much easier to understand and maintain.
  • Open/Closed Principle:
    • By disconnecting the algorithms from the elements inside the object structure, the Visitor Method conforms to the open/closed principle.
    • According to the idea of the OCP, classes should be able to be extended however they should not be able to be modified.
    • With the Visitor Method, it is possible to insert new operations or algorithms into an existing object structure without having to modify its classes, and this makes it possible to keep the existing code intact and functional.
  • Extensibility:
    • The visitor Method allows applying iterators and adding new operations to the current object, making it more flexible.
    • Contrary to the legacy system, our new abstract visitor implementation can seamlessly add a new concrete visitor just to do some extra operation on the elements without any intrusion into its current codebase.
    • Such implementation makes it easy to modify and advance the code according to the needs and ensures that the code can be applied again in many conditions.
  • Modularity:
    • The Visitor Pattern encourages modular design in that it isolates and keeps the related behavior(s) in a separate visitor implementation.
    • Visitors layer every granary visitor on a specific process or procedure, that is simple to grasp, test, and maintain.
    • Such modularity brings in standard code organization and scalability, especially in large projects that are difficult to maintain.

Disadvantage of the Visitor Design Pattern

Below are the disadvantages of visitor design pattern:

  • Increased Complexity:
    • Taking a visitor method approach requires us to determine multiple interfaces and classes, including visitor interfaces, concrete visitor implementations, and element interfaces.
    • Moreover, this extra structure might complicate the codebase, thereby making it difficult to understand and maintain even the coders who are unaware of this pattern.
  • Violation of Encapsulation:
    • In certain cases, the Visitor Pattern can be the source of encapsulation violation. As a visitor usually contains an internal state of elements that visitors need to operate on, these details should be private and, therefore, should not be exposed.
    • This violation of encapsulation might lead to a decrease in object structure integrity and make code more sensitive to changes.
  • Runtime Overhead:
    • Visitor Pattern’s dynamic dispatch mechanics combined with the overheads introduced at runtime, especially in languages with languages that do not optimize method dispatch efficiently.
    • Calling the accept method for each time introduces additional time which is being used for relaying the visit method to the visitor which is an object and the element which is an object as well.
    • The running cost of some of these tools might be insignificant in the majority of general cases, but in the cases of mission-critical ones, it can be highly consuming.





Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads