问题
I am creating a editor for different Shape Objects. I stumbled upon the visitor pattern which actually fits my needs I think.
I have a Element
class which holds a field named attrs
public class Element {
...
private Shape attrs;
...
}
My Shape
class looks like this with the visitor design pattern.
public abstract class Shape {
public abstract void accept(ShapeVisitor v);
public interface ShapeVisitor{
public void visit(CircleObject circle);
public void visit(RectangleObject rectangle);
}
}
And the actual instance of a Shape
is defined in a RectangleObject
class which extends Shape and holds the Rectangle
field. The reasoning for this structure is that I am serializing and deserializing with Jackson for a specifig JSON layout.
public class RectangleObject extends Shape {
private Rectangle rect;
public class Rectangle {
private String fill;
public String getFill() {
return fill;
}
public void setFill(String fill) {
this.fill = fill;
}
@Override
public void accept(JointShapeVisitor v) {
v.visit(this);
}
}
And finally my Editor implements the vistor methods.
public class Editor implements ShapeVisitor{
@Override
public void visit(CircleObject circle) {
}
@Override
public void visit(RectangleObject rectangle) {
}
public void setComponent(JsonArray arguments){
Element element = getFromJson(arguments);
visit(element.getAttrs()); // *** this does obv. not work ***
}
}
The element.getAttrs()
returns JointShape
, but I need here a CircleObject
or a RectangleObject
.
How can I pass the correct instance of the ShapeObject to the visit method? Am I doing something completely wrong?
Best regards.
回答1:
What you would do is
public void setComponent(JsonArray arguments){
Element element = getFromJson(arguments);
element.getAttrs().accept(this);
}
And you'll get a callback into one of the visit methods. What you don't get is a return value.
This can be a bit tricky to handle because the callback code is suddenly in no relation to the method that called the accept
method. But you often want to pass arguments back and forth between the visiting method and the method that that called accept
. To do that, you can add a little to the pattern:
@Override
public Object accept(JointShapeVisitor v, Object context) {
return v.visit(this, context);
}
}
public interface ShapeVisitor{
public Object visit(CircleObject circle, Object context);
..
}
Maybe with a bit of generics to make it typesafe. But even without you can suddenly do
public class Editor implements ShapeVisitor{
@Override
public Foo visit(CircleObject circle, Object context) {
return new Foo(circle, (String) context));
}
@Override
public void visit(RectangleObject rectangle) {
}
public void setComponent(JsonArray arguments){
Element element = getFromJson(arguments);
Foo foo = (Foo)element.getAttrs().visit(this, "Hello");
}
}
回答2:
Well ... one little mistake. Because you correctly declared an accept
method in your Shape
class, you simply must call it:
element.getAttrs().accept(this);
So simply call the accepting method of a shape by providing the editor itself as a visitor. The callback in the shape implementation will call the correct visitor mehod.
来源:https://stackoverflow.com/questions/33999177/how-to-correctly-use-the-visitor-pattern-with-different-shapes-for-an-editor