How to correctly use the visitor pattern with different Shapes for an Editor

五迷三道 提交于 2020-03-27 06:33:42

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!