Friday, November 28, 2014

Visitor Design Pattern


Summary 

Visitor Design pattern follows the open/closed principle and allows us to add new operations to be added to object structure. Open/Closed principle states that entities should be able to extend its behavior or add need new functionality without changing its own implementation.

Important Points

Visitor Design Pattern uses Double Dispatch to invoke a method at run time based on the object on which method is defined and its parameter.
Visitor represents operations or functionality to be performed on different nodes of an object structure.
Visitor Pattern  follows Open/Closed Principle.
Useful in adding new behavior or functionality to a object tree, without modifying the original Objects code.


Advantage 

We can add new functionality to the Hierarchy of Classes without changing the classes.

Disadvantage

The arguments visiting methods have to be known in advance.

Details


The participants classes in this pattern are:

Visitor (visit)-- This is an interface or an abstract class used to declare the visit operations for all the types of visitable classes.

ConcreteVisitor -- For each type of visitor all the visit methods, declared in abstract visitor, must be implemented. Each Visitor will be responsible for different operations.

Visitable (accept)-- is an interface which declares the accept operation. This is the entry point which enables an object to be “visited” by the visitor object.

ConcreteVisitable -- Those classes implements the Visitable interface or class and defines the accept operation.

Simple Use Case

This example is about  Bookmarks in Browsers. Lets assume we want to process all the bookmarks stored in all browsers and process them.

We will consider that we can have many book marks in a Browser, similarly we can have different Browsers like Firefox, Chrome, IE etc in our workstation or laptop.

Our Model Classes will represent  Workstation, Browsers and Bookmarks etc.

Let's say at some point we want to grab all the bookmarks in a Workstation across all different browsers and print them.

We can declare a Visitor (Say PrintAllBookmarks etc) and propagate through the Object chain to print them.

We can also create a different  Visitor( say Remove bookmark) which will go though the Object structure and remove bookmarks as per some condition.


Class Diagram




Sample Code 



/** Visitor Interface **/
public interface Visitor {
 void visit(WorkStation workstation);
}


/**
 * This Class represent a Workstation Object.
 * Workstation can have different Browsers installed on it.
 *
 */
public class WorkStation {

 private String name;
 
 List browsers = new ArrayList();

 public void accept(Visitor visitor) {
        visitor.visit(this);
 }
 
 
 //GETTERS and SETTERS.....
 public String getWorkstationName() {
  return name;
 }

 public void setWorkstationName(String workstationName) {
  this.name = workstationName;
 }

 public List getBrowsers() {
  return browsers;
 }

 public void addBrowser(Browser browser) {
  this.browsers.add(browser);
 }

}

/**
 * Represents a Browser Object.
 *
 */
public class Browser {
 
 private String name;
 
 List bookmarks = new ArrayList ();
 
 public Browser(String name){
  this.name = name;
 }
 
 
 //GETTERS and SETTERS.....
 public String getBrowserName() {
  return name;
 }

 public List getBookmarks() {
  return bookmarks;
 }
 
 public void addBookmark(String bookmark) {
  this.bookmarks.add(bookmark);
 }
}


/**
 * Concrete visitor implementation. It visits workstation object to read all
 * Browsers and bookmarks and returns them.
 *
 */
public class PrintNodeValueVisitor implements Visitor {
 
 StringBuilder nodeValue = new StringBuilder();

 @Override
 public void visit(WorkStation workstation) {
  StringBuilder str = new StringBuilder();
  str.append("{")
  .append("WorkStationName:").append(workstation.getWorkstationName())
  .append("{");
   str.append("Browsers [");
  for(Browser browser: workstation.getBrowsers()){
   str.append("BrowserName:").append(browser.getBrowserName());
     str.append("BookMarkDetails [");
    for(NameValuePair bookmark : browser.getBookmarks()){
     str.append("BookMarkName:");
     str. append(bookmark.name);
     str. append(",");
     str.append("BookMarkURL:");
     str.append(bookmark.value);
    }
    str.append("]");
  }
   str.append("]");
  str.append("}");
  str.append("}");
  
  nodeValue = str;
  
 }
}

Full source code can be found on github here 
https://github.com/siddharthagit/Sidd_javaprojDP/tree/master/src/dp/behavioral/visitor

No comments :

Post a Comment