From Passion to Profession
  • Home
  • Notes
  • Projects
  • Resources
    • Discovery Log
    • Books I Read
    • Blogs I Visit
    • Tools I Use
  • Home
  • Notes
  • Projects
  • Resources
    • Discovery Log
    • Books I Read
    • Blogs I Visit
    • Tools I Use

Visitor Design Pattern Example

10/10/2013

0 Comments

 
The Visitor Pattern is a behavioral design pattern that allows you to define a new operation to be applied to different classes of elements (also known as Visitable classes) without modifying those element classes directly. This pattern groups the same new operation together using a Visitor class, which contains separate member functions for each kind of Element/Visitable class.

overview

Visitor pattern lets you add a new operation to a structure of objects (Visitable/Elements) to be traversed through, without changing the Visitable/Element on which it operates.

Visitor class separates would-be virtual functions of the Visitable/Element class into a Visitor class. 

Each Visitable/Element should implement an accept(Visitor) function which delegates the request to the underlying Visitor class via calling visitor.visit(this) from accept(Visitor).

Each concrete Visitor class implements a set of visit(Object) functions that does the real work for the operation to be applied to the structure of objects. Each visit(Object) function takes in a different type of concrete Visitable/Element object. The Visitor can optionally maintain a context during a traversal.



Picture
source: GoF
Notes: 
  1. Same operations (VisitConcreteElementX()) applied to different Elements are grouped into the same Visitor.
  2. In each concrete visitor class, the VisitConcreteElementX() is not limited to apply to element of the same base type.
  3. Visitor class may even hold local state.

scenario

Consider a compiler program that deals with an abstract syntax tree. Each node in the abstract syntax tree may be a variable, an assignment, arithmetic expression, etc. For each node element, you want to apply operations like type-checking, code optimization, pretty-formatting, etc.

One way of structuring the above is to have a node class hierarchy. Within node class hierarchy, for each different node class, you define its type-checking operation, code optimization operation, and pretty-formatting operation inside the node class. This has three potential drawbacks:

  1. Adding a new operation requires adding the code to every applicable node class, probably all node classes, which requires all node classes to be recompiled.
  2. Adding a new operation to all node classes may call for redefining the interface of the node classes, which is potentially costly.
  3. Confusion, because similar operations for different node classes are not grouped together in the same class.

To avoid the above drawbacks, apply the Visitor pattern which defines two class hierarchies: one (the visitable Element hierarchy) for the nodes or data structure being operated on and one  (the Visitor hierarchy) for defining operations to be applied to the elements. The delegation of the operation from an element class to a visitor class is through an accept(Visitor) function defined in the element class.  Then in terms, calls into Visitor.visit(this). When you need to introduce a new type of operation, you'd create a new subclass in the Visitor hierarchy, without needing to modify the Element hierarchy.

visitor pattern code sample

The element/visitable interface simply defines an accept method to allow the visitor to run some action over that element - the ConcreteElement will implement this accept method. 
// Element Interface
public interface Visitable{
    public void accept(Visitor visitor); // 1

}


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


// a Visitor groups the same operation for different kind of elements
public interface Visitor {
    public void visit(Book book);
    public void visit(CD cd);
    public void visit(DVD dvd);
}


public class PostageVisitor implements Visitor {
    private double totalPostageForCart;   // 2

    //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(){      // 3 
        return totalPostageForCart;
    }
}
[1] Delegate operation applied to an element to a corresponding visitor class.
[2] Visitor class holds local state. In this case, to accumulate postage cost.
[3] Request the result of the operation/computation/local state.

comparison

Visitors over Getters?

I have reservations about embracing the concept of Visitors over Getters. In most cases, using Visitors might be excessive when a simpler approach, such as method overriding with virtual function, would suffice.

Visitor Pattern vs. Non-Visitor Pattern


  • In Visitor Pattern, introducing an operation (by introducing a new Visitor subclass) is easy, but adding an element (by introducing one new operation for each Visitor class) is hard. 
  • In Non-Visitor Pattern, introducing an operation (by introducing a new operation for each element class) is hard, but adding an element (by introducing one new element subclass) is easy. 

when to use visitor pattern

Choose to use Visitor pattern if:
  1. you want to separate out the would-be behavior into its own Visitor class
  2. you're more likely to introduce new operations and less likely to introduce new elements;
  3. you need to introduce new operation to apply to elements, but you have no access to the source code of the element hierarchy;
  4. it is possible to prepare your domain model to be able to accept visitors.

references

  • Design Patterns Uncovered: The Visitor Pattern
  • Notes, Experiences and Opinions by Richard Gomes
  • Multiple dispatch (and poor men's patter matching) in Java
0 Comments



Leave a Reply.

    Categories

    All
    Algorithm
    Concurrency
    CQ
    Data Structure
    Design Pattern
    Developer Tool
    Dynamic Programming
    Entrepreneur
    Functional Programming
    IDE
    Java
    JMX
    Marketing
    Marklogic
    Memory
    OSGI
    Performance
    Product
    Product Management
    Security
    Services
    Sling
    Social Media Programming
    Software Development

    Feed Widget

    Archives

    May 2020
    March 2020
    April 2018
    March 2018
    February 2018
    December 2017
    March 2017
    November 2016
    June 2016
    May 2016
    April 2016
    October 2015
    September 2015
    August 2015
    September 2014
    July 2014
    June 2014
    May 2014
    March 2014
    January 2014
    December 2013
    November 2013
    October 2013
    September 2013
    August 2013
    July 2013
    June 2013

    RSS Feed

in loving memory of my mother  and my 4th aunt
Photos from net_efekt, schani, visnup, Dan Zen, gadl, bobbigmac, Susana López-Urrutia, jwalsh, Philippe Put, michael pollak, oskay, Creative Tools, Violentz, Kyknoord, mobilyazilar