When do you want to use the visitor:
- A fixed number of objects that you want to be able to apply operations on.
- These objects don't currently have the ability to perform the operations needed.
- Limited ability access or change the behavior of the objects.
The basic idea of the visitor pattern is this: Starting with a group of related objects say, Shapes, where these shapes may be squares and circles etc.. which do not know how to calculate their perimeters and you either don't have access to or don't want to code the logic in the shape. Therefore we need a mechanism to calculate the perimeter (or area or other feature) without modifying the original code. However, we do have the good fortune of having each Shape implement an "accept" method which accepts a visitor.
So we develop a concrete "PerimeterShapeVisitor" which knows how to calculate the perimeter for all known shapes. This class does not know how to do anything else. Also this class must implement the special "ShapeVisitor" interface. This allows polymorphism of the java language to select which shape logic needs to be invoked. Key code samples are discussed below. The running code can be found at GIST Classic Visitor
------------------------------------------------------------------------------------------------
Classic Visitor Code
- Each shape must implement the Shape interface to "accept" a visitor e.g.
public interface Shape { void accept(ShapeVisitor v); }
- Each ShapeVisitor (e.g. the PerimeterVisitor) must implement the ShapeVisitor
public interface ShapeVisitor { void visit(Square s); void visit(Circle c); void visit(IsoscelesTriangle t); }
- And the Concrete Perimeter Visitor Looks like this:
public class PerimeterVisitor implements ShapeVisitor{ @Override public void visit(Square s) { double p = s.side()*4; System.out.println("Square perimeter: " + p); } @Override public void visit(Circle c) { double radius = c.radius(); double p = Math.PI*2*radius; System.out.println("Circle perimeter: " + p); } @Override public void visit(IsoscelesTriangle t) { double base = t.base(); double height = t.height(); double p = base+Math.sqrt(base*base + 4*height*height); System.out.println("Isosolese Triangle perimeter: " + p); } }
Running the Visitor Test:
Produces the following output:
Circle perimeter: 6.283185307179586
Square perimeter: 4.0
Isosceles Triangle perimeter: 3.23606797749979
public static void main(String[] args){ List<Shape> shapeList; shapeList = new ArrayList<>(); shapeList.add(new Circle(1)); shapeList.add(new Square(1)); shapeList.add(new IsoscelesTriangle(1, 1)); PerimeterVisitor v = new PerimeterVisitor(); for (Shape s:shapeList) { s.accept(v); } }
Circle perimeter: 6.283185307179586
Square perimeter: 4.0
Isosceles Triangle perimeter: 3.23606797749979
SEQUENCE OF EVENTS IN THE VISITOR:
- A Shape invokes the accept(v) method passing a visitor associated with whatever operation it would like to perform.
- Since Shape is an interface, polymorphism of the language will dynamically bind the "accept(v)" method associated with the concrete shape, e.g. for a Circle, the Circle's accept method will be invoked. This decision is made at run time
- The accept method will the invoke the "visit" method of the PerimeterShapeVisitor Class, and the method selected will be the Calculate
No comments:
Post a Comment
All comments are greatly appreciated! Comments will be moderated, and usually appear within 1 day. If you like a post, instead of saying you like it, vote for it or digg it (links provided). If there is any ERROR, PLEASE Comment I strive for good quality complete content.