What is Visitor Design Pattern?

Visitor is a behavioural type of design pattern. Although this is not a very popular design pattern due to its narrow applicability, it can be carefully used to resolve complex behavioural situations. This pattern is useful when an object structure contains different kinds of operations to use in different situations. Elements of an object structure will be same but the applied functionality may vary. Thus, there is no need to change any part of classes of the objects to achieve the required different operations. Also, this separation operation algorithm from object structure increases the ability to add new operations existent object structure without modifying the structures. This is a way of simplifying operations on the set of related objects.

The GoF definition,

‘Represent an operation to be performed on the elements of an object structure. The visitor pattern lets you define a new operation without changing the classes of the elements on which it operates.’

As the definitions states, pattern preserves the structure of the object, while incorporating a variety of new operations performed on the object. This is most suitable when the operations are changing frequently. In another way, pattern facilitates a way to separate the varied algorithms on one object. By that way, pattern adheres to the open/closed principle as well.

What is Visitor?

Since visitor pattern supports the multiple operations for the same object structure, there should be a clean approach to achieve this requirement. Pattern uses a separate component called ‘Visitor’ to incorporate that ability to the class hierarchy. The visitor lets the developer define new operations without modifying the classes on which it operates. It separates the operation from the object collection and implements all of the appropriate specializations of the required operation. This leads easy code maintainability and avoids the use of the instanceof operator.

Visitor Pattern Class Diagram

 

Visitor Pattern Class diagram

Components of the Visitor Pattern

Visitor

This is the interface or abstract class, which declares the common interface for all types of visitors. The visitor declares a bunch of visiting methods that accept various concrete components as parameters. This will be somewhat similar to the overloading mechanism but the types of parameters should be different hence the operations are totally different.  Visit operations will be performed on each concrete element in the object structure via the visit() method. The input concrete element type will decide the method to be called.

Concrete Visitor

These are the concrete classes, which implement all the operations described in the common visitor interface. This each concrete visitor represents a single behaviour of the object structure that is each visitor is identical with different operations. Each concrete visitor will have a natively behaving visit() method implementation.

Element (Visitable)

This is an abstract component to represent the accept operation of the visitor. It contains the accept() method and should accept visitor objects as arguments. This is considered as the entry point for the component object to be ‘visited’ by the visitor object.

ConcreteElement (ConcreteVisitable)

Concrete elements contain the actual implementation of the abstract acceptance method from the ‘Element’ component. Accept method will take a visitor object as an argument in order to redirect the call to a proper visitor’s method corresponding to the current component class.

ObjectStructure

The object structure is a class containing all the element objects, which offers a mechanism to iterate through all the elements. This object structure can be a collection or a complex structure like a composite object.

Client

The client does not know the concrete class structure of the component and just call the accept() method.

Real World Scenario

We can find several real-world examples for the visitor pattern. City visit by taxi is one example where customer orders a taxi, taxi takes the customer to different destinations based on the requirement, and there can be several types of customers who are interested in visiting various places. Shopping cart billing procedure is another scenario where cashier acts as the visitor interface and each item may contain different operations like weighting, discount reduction, attach with a warranty card or add additional items like covers and straws.

What is Double Dispatch?

Let’s think about dynamic dispatch, it is the method execution based on the runtime information. Most OO systems support dynamic dispatch via virtual methods, which are restricted by dispatching methods with single arguments. However, in some cases, you may need to dispatch methods incorporating multiple elements as method arguments. Double dispatch serves this need by adding two arguments to the method dispatch.

What is the relationship between double dispatch and the visitor pattern? The visitor pattern is a popular implementation option of the double dispatch and uses the type of the visitor object and element object as two method input parameters.

The Problem

It is a problem faced mostly in a heterogeneous object structure. Because these types of structures tend to have distinct and unrelated operations need to be performed on node objects. If we try to include those various operations in the structure without proper approach or plan, the whole system will face messy situations and difficult maintenance.

How does visitor pattern work?

Visitor act as the external caretaker for the object hierarchy that contains several types of operations. Each different object in the hierarchy connects with the visitor through the accept (visitor) method. Then, the concrete visitor takes care of the suitable operation via the input object type from the visit (element) method. It is a delegation of responsibility while the visitor reduces a lot of burden from each object node from the hierarchy.

In future, if someone needs to introduce a new behaviour to the program, it can be achieved by implementing a new visitor class and define the method in the common visitor interface.

How to Implement the Visitor Pattern?

  1. Create the Element(Component) abstract component
  2. Create Concrete Elements with accept() method
  3. Create Visitor interface with each visit() methods with concrete element types as arguments
  4. Create Concrete Visitor classes with implemented visitor methods with unique functionalities that cater specific operations.

Example for Visitor Pattern

Let’s assume a credit card scenario in a bank. The bank issues three types of credit cards for the customers. Those cards get different types of offers depending on the type of card. Card types are Silver, Gold and Platinum credit cards and the offer types are Dining, Supermarket, Hotel, and Travel. Bank system has to implement a system to incorporate those offer types to appropriate credit card types. Visitor design pattern suits best to solve this design scenario in following way.

Design pattern related class breakdown for the credit card and offer types scenario,

CreditCardVisitor: This is the base interface, which acts as the ‘Visitor’ abstract component in the design pattern.

Offer: This is the base ‘Element’ interface for the offer types object structure in the bank

Following are the concrete visitor classes to implement the abilities of each credit card type.

SilverCreditCardVisitor / GoldCreditCardVisitor                       

PlatinumCreditCardVisitor / DinningOffer

Following are the concrete offer type classes to differentiate each offer validities.

Dining Offer/ SupermarketOffer / HotelOffer /  TravelOffer     

 ‘Offer’ interface allows the ‘CreditCardVisitor’ interface to pass the right object so the correct operation occurs on the right type of object. The accept() method in ‘Offer’ interface pass the same abstract visitor object and later specialized version of visit() method is called. Method overloading is used at this position to select the appropriate visit() method.

Class Diagram for the Credit Card Offers System

Visitor pattern creditcards

 

Code samples for credit card offers scenario

CreditCardVisitor.java

Offer.java

SilverCreditCardVisitor.java

GoldCreditCardVisitor.java

PlatinumCreditCardVisitor.java

DinningOffer.java

SuperMarketOffer.java

HotelOffer.java

TravelOffer.java

When to use the Visitor Design Pattern

  • When there is a complex object structure with many classes and different interface and client needs to perform several operations on these objects depending on their concrete classes.
  • When the operations are distinct and unrelated with one another it’s easy to keep organized the classes and operations using this pattern.
  • When the classes in the object structure rarely change but there is a need to define new operations over the structure.
  • When there is a need for adding a new operation to the visitor hierarchy or new component to the object structure we can achieve it by not polluting the existing design

Visitor Pattern Limitations

  • It’s necessary to know the return type of visit() methods at the time of designing the pattern otherwise we have to change the interface and all of its implementations.
  • It contains many implementations for the visitor interface, which makes it harder to extend.
  • If one new element object is added to the system, we have to change all the implemented visitor classes.

Leave a Reply