如何为编辑器正确使用具有不同形状的访问者模式

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

我正在为不同的形状对象创建一个编辑器。我偶然发现了我认为真正符合我需求的访问者模式。
我有一个 Element class 包含一个名为 attrs

的字段
public class Element {
    ...   
    private Shape attrs;
    ...
}

我的 Shape class 使用访问者设计模式看起来像这样。

public abstract class Shape {
    public abstract void accept(ShapeVisitor v);

    public interface ShapeVisitor{
        public void visit(CircleObject circle);
        public void visit(RectangleObject rectangle);
    }
}

Shape 的实际实例在 RectangleObject class 中定义,它扩展了 Shape 并包含 Rectangle 字段。这种结构的原因是我正在使用 Jackson 序列化和反序列化特定 JSON 布局。

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);
      }
    }

最后,我的编辑器实现了访问者方法。

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 ***
    }
}

element.getAttrs() returns JointShape 但是我这里需要一个CircleObject 或者一个RectangleObject.


如何将正确的 ShapeObject 实例传递给访问方法?我做错了什么吗?

此致。

嗯...一个小错误。因为您在 Shape class 中正确地声明了一个 accept 方法,您只需调用它:

element.getAttrs().accept(this);

因此只需将编辑器本身作为访问者来调用形状的接受方法。形状实现中的回调将调用正确的访问者方法。

你会做的是

public void setComponent(JsonArray arguments){
  Element element = getFromJson(arguments);
  element.getAttrs().accept(this);
}

并且您将获得对其中一种访问方法的回调。您没有得到的是 return 值。

处理起来可能有点棘手,因为回调代码突然与调用 accept 方法的方法无关。但是您经常希望在访问方法和调用 accept 的方法之间来回传递参数。为此,您可以在模式中添加一点:

@Override
public Object accept(JointShapeVisitor v, Object context) {
    return v.visit(this, context);
  }
}

public interface ShapeVisitor{
    public Object visit(CircleObject circle, Object context);
    ..
}

也许使用一些泛型来使其类型安全。但即使没有你也可以突然做

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");
    }
}