591698 members! Sign up to stay informed.

Sponsored Links


Resources

Enterprise Java
Research Library

Get Java white papers, product information, case studies and webcasts

J2EE patterns J2EE patterns J2EE patterns Messages: 6 Messages: 6 Messages: 6 Printer friendly Printer friendly Printer friendly Post reply Post reply Post reply XML XML XML

Compositional Visitor

Posted by: Alex Bacon on Mon Jan 08 01:24:14 EST 2007 DIGG
Overview:

The Compositional Visitor replaces the Visitor class hierarchy with a compositional pattern where each Visitable object has its own (very simple) Visitor interface - and each Visitor picks and chooses which Visitor interfaces it implements and hence which elements it operates on. If a Visitor does not need to process a particular element then it does not implement its associated Visitor interface. Knowledge of the standard Visitor Pattern is assumed.


Background:

The traditional Visitor pattern is flawed for many real world applications as it scales badly. As it says in Design Patterns:

Consequences (of the Visitor Pattern):
3. Adding new ConcreteElement classes is hard.... each new ConcreteElement gives rise to a new abstract operation on Visitor and a corresponding implementation in each ConcreteVisitor class.

You are left with two choices either:
a) You have a separate Visitor interfaces (or class hierarchies) for each 'type' of Visitor. (Visitors of the same 'type' being Visitors that process the same elements) - and a corresponding Visitable interface for each 'type', or
b) (The orthodox approach) Implement visit(element) for every possible (Visitable) element in every Visitor.

Neither way is elegant. It is possible to have a class hierarchy of Visitors with a superclass that implements default implementations of visit for every Visitable element; but this is far from ideal as that superclass still needs to be maintained and the Visitors are aligned in a hierarchy based on the fact that they are Visitors not based on their role or requirements within the application.

In essence the Visitors and Visitable objects should be INDEPENDENT - so the Visitable objects should not care if a new Visitor is added - and a Visitor should not care if a new Visitable object is added. Furthermore the Visitors themselves should be independent - unless they share common processing requirements.


Compositional Visitor Pattern:

The secret to making the Visitors and Visitable objects independent is to use composition. There is only one visitable interface:

public interface Visitable {
public Object accept(Object visitor) throws Exception;
}

Each visitable element has its own Visitor interface (which could potentially be created using code generation as they are very simple) e.g.

public interface Element1Visitor {
public Object visit(Element1 visitable) throws Exception;
}

public interface Element2Visitor {
public Object visit(Element2 visitable) throws Exception;
}

Each Visitable element implements Visitable. The accept method checks to see if the visitor implements its Visitor - if so then is passes itself to the Visitor for processing - if not then it either passes the request up the class hierarchy (if the superclass implements Visitable) or returns null (or conceivably throws a checked NotProcessableByVisitorException).

public class Element1 implements Visitable {

//Other properties and methods

public Object accept(Object visitor) throws Exception {
if (visitor instanceof Element1Visitor) {
return ((Element1Visitor)visitor).visit(this);
}
else {
return null;
//For subclasses of Visitable classes
// return super.accept(visitor)
}
}
}


public class Element2 implements Visitable{

//Other properties and methods

public Object accept(Object visitor) throws Exception {
if (visitor instanceof Element2Visitor) {
return ((Element2Visitor)visitor).visit(this);
}
else {
return null;
//For subclasses of Visitable classes
// return super.accept(visitor)
}
}
}

The Visitor itself simply implements the Visitor interfaces for the Visitable Elements it can process:

public class SampleVisitor implements Element1Visitor, Element2Visitor {

public Object visit(Element1 visitable) throws Exception {
Object result = null;
//Do work for element1
return result;
}

public Object visit(Element2 visitable) throws Exception {
Object result = null;
//Do work for element2
return result;
}
}

The Visitor can then be used as normal:
SampleVisitor sampleVisitor = new SampleVisitor();
for (Visitable visitable : visitableObjects){
visitable.accept(sampleVisitor);
}


Conclusion

Whilst this pattern does create some additional classes (the extra Visitor interfaces) - they are simple and could be automatically generated. It also has a more complex accept method than just a straight callback to the Visitor; but it is far from complicated and only needs to be written once to handle all possible Visitors. The big benefit, on the other hand, is that you can use the Visitor pattern without worrying about adding new Visitable elements or Visitors. In fact ANY class can become a visitor just by implementing the appropriate interfaces for whatever elements you want to process. Visitors become cheap and easy.

But why use the Visitor pattern anyway? Because Visitors are a great way to centralise specific processing and remove logic (especially business logic) from model objects. This is a boon for Test Driven Development because
a) It assists with keeping certain classes (e.g. model objects) clean and free from processing logic so they can then be used freely throughout test code without worrying about mocking them or about their behaviour changing.
b) The processing logic is all in one spot (the Visitor) and hence can be more easily, and neatly, tested than if it were scattered throughout the Visitable entities.

I believe that in general putting logic within model classes is bad idea - and as soon as other system resources are required (e.g. a Rules Engine) you cannot put the logic there. Visitors offer - to my mind - a much more elegant solution.

Threaded replies

·  Compositional Visitor by Alex Bacon on Mon Jan 08 01:24:14 EST 2007
  ·  Re: Compositional Visitor by James Watson on Tue Jan 09 13:58:38 EST 2007
  ·  Re: Compositional Visitor by James Watson on Tue Jan 09 15:07:27 EST 2007
  ·  Re: Compositional Visitor by Alex Bacon on Tue Jan 09 20:26:12 EST 2007
    ·  Re: Compositional Visitor by James Watson on Wed Jan 10 10:06:00 EST 2007
  ·  Re: Compositional Visitor by Alex Bacon on Tue Jan 09 20:28:03 EST 2007
  ·  This has already been discovered by Alex Bacon on Tue Jan 30 00:49:39 EST 2007
  Message #225163 Post reply Post reply Post reply Go to top Go to top Go to top

Re: Compositional Visitor

Posted by: James Watson on Tue Jan 09 13:58:38 EST 2007 in response to Message #225031
reposting code example with presentation formatting:


public interface Visitable {
public Object accept(Object visitor) throws Exception;
}

Each visitable element has its own Visitor interface (which could
potentially be created using code generation as they are very simple) e.g.

public interface Element1Visitor {
public Object visit(Element1 visitable) throws Exception;
}

public interface Element2Visitor {
public Object visit(Element2 visitable) throws Exception;
}

Each Visitable element implements Visitable. The accept method checks to see
if the visitor implements its Visitor - if so then is passes itself to the
Visitor for processing - if not then it either passes the request up the class
hierarchy (if the superclass implements Visitable) or returns null (or
conceivably throws a checked NotProcessableByVisitorException).

public class Element1 implements Visitable {
//Other properties and methods

public Object accept(Object visitor) throws Exception {
if (visitor instanceof Element1Visitor) {
return ((Element1Visitor)visitor).visit(this);
} else {
return null;
//For subclasses of Visitable classes
// return super.accept(visitor)
}
}
}


public class Element2 implements Visitable{
//Other properties and methods

public Object accept(Object visitor) throws Exception {
if (visitor instanceof Element2Visitor) {
return ((Element2Visitor)visitor).visit(this);
} else {
return null;
//For subclasses of Visitable classes
// return super.accept(visitor)
}
}
}

The Visitor itself simply implements the Visitor interfaces for the
Visitable Elements it can process:

public class SampleVisitor implements Element1Visitor, Element2Visitor {
public Object visit(Element1 visitable) throws Exception {
Object result = null;
//Do work for element1
return result;
}

public Object visit(Element2 visitable) throws Exception {
Object result = null;
//Do work for element2
return result;
}
}

The Visitor can then be used as normal:

SampleVisitor sampleVisitor = new SampleVisitor();

for (Visitable visitable : visitableObjects){
visitable.accept(sampleVisitor);
}


  Message #225169 Post reply Post reply Post reply Go to top Go to top Go to top

Re: Compositional Visitor

Posted by: James Watson on Tue Jan 09 15:07:27 EST 2007 in response to Message #225031
I like this idea except for the instanceof checks.

What about having a method on the Vistable interface like this:

public interface Visitable {
Object accept(Object visitor) throws Exception;
Class visitorType();
}


Then the Vistor can determine whether they are able to visit the visitable before calling it. Then the Visitable can just cast to the right type. With generics, the cast can also be removed.

  Message #225186 Post reply Post reply Post reply Go to top Go to top Go to top

Re: Compositional Visitor

Posted by: Alex Bacon on Tue Jan 09 20:26:12 EST 2007 in response to Message #225031
There are many ways to skin the proverbial cat here - I chose the instanceof solution for my example as it is the simplest to understand and leaves the interfaces looking like the standard Visitor pattern ones. The 'interesting' implementation of generics used in Java prevents you having a generic Visitor<visitee> interface unfortunately. MyVisitor implements Visitor<ClassA>, Visitor<ClassB> causes a compilation error because type erasure makes the two interfaces look identical. (Queue much growling).

Having the visitor decide whether it can be processed by the visitee is an interesting option though. You may still need to consider checking the superclass as well - it may be that visitor implements the interface corresponding to the superclass rather than the actual object class.

Either way - the fundimental point of the pattern - composing the visitor from multiple visitor interfaces remains the same.

  Message #225187 Post reply Post reply Post reply Go to top Go to top Go to top

Re: Compositional Visitor

Posted by: Alex Bacon on Tue Jan 09 20:28:03 EST 2007 in response to Message #225031
Thank you for reformatting the code by the way.

  Message #225210 Post reply Post reply Post reply Go to top Go to top Go to top

Re: Compositional Visitor

Posted by: James Watson on Wed Jan 10 10:06:00 EST 2007 in response to Message #225186
There are many ways to skin the proverbial cat here - I chose the instanceof solution for my example as it is the simplest to understand and leaves the interfaces looking like the standard Visitor pattern ones. The 'interesting' implementation of generics used in Java prevents you having a generic Visitor<visitee> interface unfortunately. MyVisitor implements Visitor<ClassA>, Visitor<ClassB> causes a compilation error because type erasure makes the two interfaces look identical. (Queue much growling).


You'd have to use explicit casts and ignore the warnings on the visitor side. The benefit is only on the visitee side. This is unfortunately what we have to work with, I'm done growling about it.

Having the visitor decide whether it can be processed by the visitee is an interesting option though. You may still need to consider checking the superclass as well - it may be that visitor implements the interface corresponding to the superclass rather than the actual object class.


You can use the isAssignable() method in Class. The other thing this allows for is an easy way to implement a true compositional visitor. That is, the visitor doesn't actually implement the visitee interfaces but is composed of individual visitor instances that do. I'll put some code up later.

I love the concept. I think this could be a really useful thing. At least in Java. You could also probably use this to implement a Compositional Builder too. I was going to mention before that in yor original post you seem to be talking about the Builder pattern more than the visitor. The visitor pattern is usually used to emulate multiple-dispatch

  Message #226409 Post reply Post reply Post reply Go to top Go to top Go to top

This has already been discovered

Posted by: Alex Bacon on Tue Jan 30 00:49:39 EST 2007 in response to Message #225031
See: http://objectmentor.com/resources/articles/visitor.pdf - where it is termed Acyclic Visitor. There is no date on the article - but I assume it predates my invention of this pattern.

J2EE PatternsJ2EE PatternsJ2EE Patterns
Patterns

We are proud to provide this patterns/strategies repository to the community. Feel free to post any useful design tips you know!

EJB Design Patterns PDFEJB Design Patterns PDFEJB Design Patterns PDF

EJB Design Patterns is now available for free download in PDF format. The book contains a catalog of twenty advanced EJB patterns and provides strategies for mapping application requirements to patterns-driven design, J2EE development best practices, and more. EJB Design Patterns was the #2 book at Java One 2002, and held the #1 Java book position on Amazon.com for weeks since the book was released in March. Download your PDF here.
Useful patterns around the webUseful patterns around the webUseful patterns around the web
Patterns

EntityBeansAsDomainObjects

This essential pattern describes how to model your entity beans.

The Aggregate Entity pattern

How to make an entity bean a facade to a set of dependent objects.

EJB Unit Testing Strategies

Every guru should use unit testing.

Other Patterns sitesOther Patterns sitesOther Patterns sites

Portland Patterns Repository

The original reference site for patterns. Frequented by the gang of 4 and their mentors (Kent Beck, Ward Cunningham).

Sun Java Center Patterns

A catalogue of J2EE design patterns from Suns Consulting Division.

IBM Patterns for e-Business

A catalogue of high level business, architectural and topological patterns for large scale systems.

J2EE Blueprints Patterns

Design Patterns from the J2EE Blueprints, Suns authoritative guide to J2EE development.


News | Blogs | Discussions | Tech talks | Patterns | Reviews | White Papers | Downloads | Articles | Media kit | About
All Content Copyright ©2007 TheServerSide Privacy Policy
Site Map