DynamicDispatcher API

The dynamic dispatcher library, version 0.0.4.

See:
          Description

Packages
net.sourceforge.dynamicdispatch  
net.sourceforge.dynamicdispatch.bytecode  
net.sourceforge.dynamicdispatch.helper  
net.sourceforge.dynamicdispatch.reflection  
net.sourceforge.dynamicdispatch.sourcecode  

 

The dynamic dispatcher library, version 0.0.4.

This is preliminary documentation! It will be completed before the first 0.1 release.

This project was initially based on this paper (to be published in the ACM proceedings of the SEKE'04 conference).

Dynamic Dispatcher is a replacement for applying the VISITOR design pattern. It can be used to define new operations (called visitors) over unmodifiable (domain) class hierarchies.
Summarized, the accept method of the VISITOR pattern is replaced by an explicit dispatcher object.

Furthermore, the dispatcher object simulates covariant method overriding. Thus a visitor class does not neccessarily define visit methods for all domain classes. Instead, the most appropriate visit method is chosen during dispatch. E.g., dispatch(anArrow) calls visit(Line) if visit(Arrow) is not defined in the visitor (see example below).

The library provides three concrete dispatcher factories to create a dispatcher for a certain object. The default (ReflectionDispatcherFactory) uses reflection. It does not require additional libraries.

When performance is an issue (e.g., when a large number of incocations must be dispatched), the ByteCodeDispatcherFactory (requires bcel.jar) and the SourceCodeDispatcherFactory (require tools.jar) can be used.

Example

The following example illustrates how this library can be used. It consists of

Because arrows are translated the same way as lines (if translate() would be defined inside the Shape hierarchy it would not have been overridden in Arrow), we do not provide a visit(Arrow a) method It can be seen, that we do not have to modify Shape and co. in order to realize translate. If we had applied the standard VISITOR pattern, this is not possible. We had to explicitly define visit(Arrow a) which then could call visit((Line)a).

  abstract class Shape {}
  
  class Line extends Shape { float x1,y1,x2,y2; /* ... */ }
  
  class Circle extends Shape { float x,y,r; /* ... */ }
  
  class Picture extends Shape { ArrayList elements = new ArrayList(); /* ... */ }

  class Arrow extends Line {  /* ... */  }
  
  class Translate {
    float x,y;
	// select the default dispatcher for "visit" methods
    Dispatcher dsp = DispatcherFactory.createDefaultDispatcher(this);

    public void dispatch(Shape s) { dsp.dispatch(s); }

    public void visit(Line l) { l.x1+=x;l.y1+=y; l.x2+=x;l.y2+=y; }

    public void visit(Circle c) { c.x+=x;c.y+=y; }

    public void visit(Picture p) { 
      for (Iterator it=p.elements;it.hasNext();) {
        Shape s = (Shape)it.next();
        dsp.dispatch(s);
      }
    }
  
    // no visit(Arrow), it is handled by visit(Line) !!
  }

  ...

  public static void main(String[] args) {
    Picture p = new Picture();
    Arrow a = new Arrow(1.0,1.0,2.0,4.0);
    Circle c = new Circle(1.0,2.0,3.0);
    p.add(a);p.add(c);
    Translate t = new Translate(1.0,2.0);
    t.dispatch(p);
  }