DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Low-Code Development: Leverage low and no code to streamline your workflow so that you can focus on higher priorities.

DZone Security Research: Tell us your top security strategies in 2024, influence our research, and enter for a chance to win $!

Launch your software development career: Dive head first into the SDLC and learn how to build high-quality software and teams.

Open Source Migration Practices and Patterns: Explore key traits of migrating open-source software and its impact on software development.

Related

  • The Complete Guide to Stream API and Collectors in Java 8
  • Distributed Java Collections in Redis With Redisson
  • Java: Why a Set Can Contain Duplicate Elements
  • What Is Ant, Really?

Trending

  • Leveraging Microsoft Graph API for Unified Data Access and Insights
  • Front-End Application Performance Monitoring (APM)
  • Performance and Scalability Analysis of Redis and Memcached
  • PostgreSQL BiDirectional Replication
  1. DZone
  2. Coding
  3. Languages
  4. Visitor Pattern Tutorial with Java Examples

Visitor Pattern Tutorial with Java Examples

Learn the Visitor Design Pattern with easy Java source code examples as James Sugrue continues his design patterns tutorial series, Design Patterns Uncovered

By 
James Sugrue user avatar
James Sugrue
DZone Core CORE ·
Mar. 09, 10 · Tutorial
Like (23)
Save
Tweet
Share
378.0K Views

Join the DZone community and get the full member experience.

Join For Free

Today we're going to take a look at the Visitor pattern. Of all of the patterns that I've used so far, Visitor is by far the most powerful and convenient.  

Vistors in the Real World 

A real world analogy always helps with the understanding of a design pattern. One example I have seen for the Visitor pattern in action is a taxi example, where the customer calls orders a taxi, which arrives at his door. Once the person sits in, the visiting taxi is in control of the transport for that person. 

Shopping in the supermarket is another common example, where the shopping cart is your set of elements. When you get to the checkout, the cashier acts as a visitor, taking the disparate set of elements (your shopping), some with prices and others that need to be weighed, in order to provide you with a total. 

It's a difficult pattern to explain in the real world, but things should become clearer as we go through the pattern definition, and take a look at how to use it in code.  

Design Patterns Refcard
For a great overview of the most popular design patterns, DZone's Design Patterns Refcard is the best place to start. 

The Visitor Pattern

The Visitor is known as a behavioural pattern,as it's used to manage algorithms, relationships and responsibilities between objects. Thedefinition of Visitor provided in the original Gang of Four book on DesignPatterns states: 

 Allows for one or more operation to be applied to a set of objects at runtime, decoupling the operations from the object structure.  

What the Visitor pattern actually does is create an external class that uses data in the other classes. If you need to perform operations across a dispate set of objects, Visitor might be the pattern for you. The GoF book says that the Visitor pattern can provide additional functionality to a class without changing it. Let's see how that can work, first by taking a look at the classic diagram definition of  the Visitor pattern:

Image title


The core of this pattern is the Visitor interface. This interface defines a visit operation for each type of ConcreteElement in the object structure. Meanwhile, the ConcreteVisitor implements the operations defined in the Visitor interface. The concrete visitor will store local state, typically as it traverses the set of elements. The element interface simply defines an accept method to allow the visitor to run some action over that element - the ConcreteElement will implement this accept method. 


Where Would I Use This Pattern?

The pattern should be used when you have distinct and unrelated operations to perform across a structure of objects. This avoids adding in code throughout your object structure that is better kept seperate, so it encourages cleaner code. You may want to run operations against a set of objects with different interfaces.  Visitors are also valuable if you have to perform a number of unrelated operations across the classes.

In summary, if you want to decouple some logical code from the elements that you're using as input, visitor is probably the best pattern for the job.

So How Does It Work In Java?

The following example shows a simple implementation of the pattern in Java. The example we'll use here is a postage system. Our set of elements will be the items in our shopping cart. Postage will be determined using the type and the weight of each item, and of course depending on where the item is being shipped to. 

Let's create a seperate visitor for each postal region. This way, we can seperate the logic of calculating the total postage cost from the items themselves. This means that our individual elements don't need to know anything about the postal cost policy, and therefore, are nicely decoupled from that logic. 

First, let's create our general visitable  interface: 

//Element interface
public interface Visitable{
  public void accept(Visitor visitor);
}

Now, we'll create a concrete implementation of our interface, a Book.

//concrete element
public class Book implements Visitable{
  private double price;
  private double weight;

  //accept the visitor
  public void accept(Visitor vistor) {
    visitor.visit(this);
  }
  public double getPrice() {
    return price;
  }
  public double getWeight() {
    return weight;
  }
} 

As you can see it's just a simple POJO, with the extra accept method added to allow the visitor access to the element. We could add in other types here to handle other items such as CDs, DVDs or games.


Now we'll move on to the Visitor interface. For each different type of concrete element here, we'll need to add a visit method. As we'll just deal with Book for now, this is as simple as:

public interface Visitor{
  public void visit(Book book);
  
  //visit other concrete items
  public void visit(CD cd);
  public void visit(DVD dvd);
}

The implementation of the Vistor can then deal with the specifics of what to do when we visit a book. 

public class PostageVisitor implements Visitor {
  private double totalPostageForCart;
  //collect data about the book
  public void visit(Book book) {
    //assume we have a calculation here related to weight and price
    //free postage for a book over 10 
    if(book.getPrice() < 10.0) {
      totalPostageForCart += book.getWeight() * 2;
    }
  }

  //add other visitors here
  public void visit(CD cd) {...}
  public void visit(DVD dvd) {...}

  //return the internal state
  public double getTotalPostage() {
    return totalPostageForCart;
  }
} 

As you can see it's a simple formula, but the point is that all the calculation for book postage is done in one central place. 

To drive this visitor, we'll need a way of iterating through our shopping cart, as follows: 

public class ShoppingCart {
  //normal shopping cart stuff
  private ArrayList<Visitable> items;
  public double calculatePostage() {
    //create a visitor
    PostageVisitor visitor = new PostageVisitor();
    //iterate through all items
    for(Visitable item: items) {
      item.accept(visitor);
    }
    double postage = visitor.getTotalPostage();
    return postage;
  }
}

Note that if we had other types of item here, once the visitor implements a method to visit that item, we could easily calculate the total postage.

So, while the Visitor may seem a bit strange at first, you can see how much it helps to clean up your code. That's the whole point of this pattern - to allow you seperate out certain logic from the elements themselves, keeping your data classes simple.

Watch Out for the Downsides

The arguments and return types for the visiting methods needs to be known in advance, so the Visitor pattern is not good for situtations where these visited classes are subject to change. Every time a new type of Element is added, every Visitor derived class must be amended. 

Also, it can be difficult to refactor the Visitor pattern into code that wasn't already designed with the pattern in mind. And, when you do add your Visitor code, it can look obscure. The Visitor is powerful, but you should make sure to use it only when necessary.   

Next Up

Later on this week, we're going to visit the Proxy pattern.

Enjoy the Whole "Design Patterns Uncovered" Series:

Creational Patterns

  • Learn The Abstract Factory Pattern
  • Learn The Builder Pattern
  • Learn The Factory Method Pattern
  • Learn The Prototype Pattern

Structural Patterns

  • Learn The Adapter Pattern
  • Learn The Bridge Pattern
  • Learn The Decorator Pattern
  • Learn The Facade Pattern
  • Learn The Proxy Pattern

Behavioral Patterns

  • Learn The Chain of Responsibility Pattern
  • Learn The Command Pattern
  • Learn The Interpreter Pattern
  • Learn The Iterator Pattern
  • Learn The Mediator Pattern
  • Learn The Memento Pattern
  • Learn The Observer Pattern
  • Learn The State Pattern
  • Learn The Strategy Pattern
  • Learn The Template Method Pattern
  • Learn The Visitor Pattern
Visitor pattern Java (programming language) Element Interface (computing) Object (computer science)

Opinions expressed by DZone contributors are their own.

Related

  • The Complete Guide to Stream API and Collectors in Java 8
  • Distributed Java Collections in Redis With Redisson
  • Java: Why a Set Can Contain Duplicate Elements
  • What Is Ant, Really?

Partner Resources


Comments

ABOUT US

  • About DZone
  • Send feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: