The Visitor Design Pattern

The Visitor Design Pattern
The visitor design pattern allows us to add operations to objects that already exist without modifying their classes and without extending them.

The Visitor design pattern is one of the classic design patterns covered by the Design Patterns: Elements of Reusable Object-Oriented Software book. This books sets the foundation for the classic design patterns software developers are usually familiar with. 

How to Learn Design Patterns

There are many resources for learning design patterns. You can find various books, video clips and blogs that cover this topic. Nevertheless, many of them are a bit inaccurate in their texts compared with the Design Patterns: Elements of Reusable Object-Oriented Software book. Therefore, it is always recommended to keep a copy of that book and use it as the ultimate reference when learning this topic. 

The Visitor Design Pattern

The Visitor design pattern provides a solution for the following programming problem: How to add functionality to existing objects without changing the code of the classes they were created from? When dealing with Python and JavaScript we can easily and dynamically add new functions to objects that already exist. When dealing with C#, Kotlin, and Scala, we can easily define new functions as an extension for a specific type, and by doing so, add more operations (functionalities) we will be able to perform on objects instantiated from that type. 

The following code sample includes the abstract class Element, and the XMLElement and the JSONElement classes that extend it.

				
					public abstract class Element {
    public abstract void accept(Visitor visitor);
}
				
			
				
					public class JSONElement extends Element {

    private int id;

    public JSONElement(int id) {
        this.setId(id);
    }

    public void accept(Visitor v) {
        v.visit(this);
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}
				
			
				
					public class XMLElement extends Element{

    private int id;

    public XMLElement(int id) {
        this.setId(id);
    }



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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}
				
			

The Element abstract class includes the definition of the accept() method. This method takes a Visitor object. Visitor is an interfaces, implemented by classes. Each class that implements Visitor describes a specific operation. We can implement Visitor as many times as we want.  

				
					public interface Visitor {
    public void visit(Element element);
}
				
			
				
					public class ElementCheckingIDVisitor implements Visitor {

    public void visit(XMLElement xe) {
        System.out.println(
                "processing an XML element " + xe.getId());
        System.out.println("checking the id is OK");
        if(xe.getId()>99 && xe.getId()<100000) {
            System.out.println("id is ok");
        } else {
            System.out.println("id is not ok");
        }
    }

    public void visit(JSONElement je) {
        System.out.println(
                "processing a JSON element " + je.getId());
        System.out.println("checking the id is OK");
        if(je.getId()>99 && je.getId()<100000) {
            System.out.println("id is ok");
        } else {
            System.out.println("id is not ok");
        }
    }

    @Override
    public void visit(Element element) {
        if(element instanceof JSONElement) {
            visit((JSONElement) element);
        } else if(element instanceof XMLElement) {
            visit((XMLElement) element);
        }
    }
}
				
			
				
					public class ElementMultiplyingIDBy10Visitor implements Visitor {
    public void visit(XMLElement xe) {
        System.out.println(
                "processing an XML element " + xe.getId());
        xe.setId(10*xe.getId());
        System.out.println("the new id is " + xe.getId());
    }

    public void visit(JSONElement je) {
        System.out.println(
                "processing a JSON element " + je.getId());
        je.setId(10*je.getId());
        System.out.println("the new id is " + je.getId());
    }

    @Override
    public void visit(Element element) {
        if(element instanceof JSONElement) {
            visit((JSONElement) element);
        } else if(element instanceof XMLElement) {
            visit((XMLElement) element);
        }
    }
}
				
			

In order to get a good demo for the Visitor design pattern, let’s create a list of Element objects and use a Visitor object we can use to visit each one of the Element object using a simple loop. The Visitor object visits an Element object when the accept method is invoked on the Element object and the reference for the Visitor object is passed over to it. Inside the accept method we can invoke the visit method on the Visitor object passing over the reference for the Element object. 

				
					public class Document extends Element {

    public List<Element> elements = new ArrayList<>();

    @Override
    public void accept(Visitor v) {
        for (Element e : this.elements) {
            e.accept(v);
        }
    }
}
				
			
				
					public class VisitorDemo {

    public static void main(String[] args) {

        //Visitor v = new ElementCheckingIDVisitor();
        Visitor v = new ElementMultiplyingIDBy10Visitor();

        Document d = new Document();
        d.elements.add(new JSONElement(534));
        d.elements.add(new JSONElement(234));
        d.elements.add(new XMLElement(9789));
        d.elements.add(new XMLElement(7877));
        d.elements.add(new JSONElement(645));

        d.accept(v);
        d.accept(v);
    }

}
				
			
Professional Training

We, at life michael, continuously develop new professional seminars for software developers in various topics, including the design patterns topic. Most of the classic design patterns can be implemented (nearly) in every programming language. As a result, we chose to develop dedicated separated seminars for learning this topic in various programming languages, such as the Design Patterns in PythonDesign Patterns in KotlinDesign Patterns in Java, and the Design Patterns in C#. Apart of the dedicated seminars for learning the classic design patterns, we also continuously develop professional seminars that cover design patterns beyond the classic ones, such as the Combinator Design Pattern as well as many other related seminars, such as a seminar about Anti Patterns and a seminar about the SOLID Design Principles.  

We at life michael, continuously develop new professional seminars and new professional courses. You can find detailed information about the courses and the seminars we developed so far at life michael.

Share:

What are Anti Patterns?

Anti Patterns

Unlike design patterns, anti patterns just seem to be a solution. However, they are not a solution and they cause additional costs.

Virtual Threads in Java Professional Seminar

Virtual Threads in Java

The use of virtual threads can assist us with improving the performance of our code. Learn how to use virtual threads effectively.

NoSQL Databases Courses, Seminars, Consulting, and Development

MongoDB Design Patterns Meetup

The use of MongoDB involves with various cases in which we can overcome performance issues by implementing specific design patterns.

image of woman and database

Record Classes in Java

Learn how to define record classes in Java, and when to use record classes in your code. Stay up to date with the new Java features.

The Beauty of Code

Coding is Art! Developing Code That Works is Simple. Develop Code with Style is a Challenge!

Skip to content Update cookies preferences