java - 使用访问者模式时是匿名还是真实的类定义?

标签 java design-patterns visitor-pattern

当您使用访问者模式并且需要在访问者方法中获取变量时,如何继续?

我看到两种方法。第一个使用匿名类:

// need a wrapper to get the result (which is just a String)
final StringBuild result = new StringBuilder();
final String concat = "Hello ";

myObject.accept(new MyVisitor() {

    @Override
    public void visit(ClassA o)
    {
        // this concatenation is expected here because I've simplified the example
        // normally, the concat var is a complex object (like hashtable) 
        // used to create the result variable 
        // (I know that concatenation using StringBuilder is ugly, but this is an example !)
        result.append(concat + "A");
    }

    @Override
    public void visit(ClassB o)
    {
        result.append(concat + "B");
    }
});

System.out.println(result.toString());

优点和缺点:

  • 优点:您不需要为这个小行为创建类文件
  • 缺点:我不喜欢这种情况下的“final”关键字:匿名类的可读性较差,因为它调用外部变量,并且您需要使用包装器来获取请求的值(因为使用关键字final,您无法重新分配变量)

另一种方法是创建一个外部访问者类:

public class MyVisitor
{
    private String result;
    private String concat;

    public MyVisitor(String concat)
    {
        this.concat = concat;
    }

    @Override
    public void visit(ClassA o)
    {
        result = concat + "A";
    }

    @Override
    public void visit(ClassB o)
    {
        result = concat + "B";
    }

    public String getResult()
    {
        return result;
    }
}

MyVisitor visitor = new MyVisitor("Hello ");
myObject.accept(visitor);
System.out.println(visitor.getResult());

优点和缺点:

  • 优点:所有变量都在干净的范围内定义,您不需要包装器来封装请求的变量
  • 缺点:需要外部文件,必须在accept方法之后调用getResult()方法,这非常难看,因为您需要知道函数调用顺序才能正确使用访问者

您,在这种情况下您的做法是什么?首选方法?另一个想法?

最佳答案

嗯,这两种方法都是有效的,而且在我看来,这实际上取决于您是否愿意重用代码。顺便说一句,您的最后一个“缺点”点并不完全有效,因为您不需要“外部文件”来声明类。它很可能是一个内部类......

也就是说,我使用访客的方式是这样的:

public interface IVisitor<T extends Object> {
    public T visit(ClassA element) throws VisitorException;
    public T visit(ClassB element) throws VisitorException;
}

public interface IVisitable {
    public <T extends Object> T accept(final IVisitor<T> visitor) throws VisitorException;
}

public class MyVisitor implements IVisitor<String> {
    private String concat;

    public MyVisitor(String concat) {
        this.concat = concat;
    }

    public String visit(ClassA classA) throws VisitorException {
        return this.concat + "A";
    }

    public String visit(ClassB classB) throws VisitorException {
        return this.concat + "B";
    }
}

public class ClassA implements IVisitable {
    public <T> T accept(final IVisitor<T> visitor) throws VisitorException {
        return visitor.visit(this);
    }
}

public class ClassB implements IVisitable {
    public <T> T accept(final IVisitor<T> visitor) throws VisitorException {
        return visitor.visit(this);
    }
}

// no return value needed?
public class MyOtherVisitor implements IVisitor<Void> {
    public Void visit(ClassA classA) throws VisitorException {
        return null;
    }

    public Void visit(ClassB classB) throws VisitorException {
        return null;
    }
}

这样,被访问的对象不知道访问者想要用它们做什么,但它们确实返回访问者想要返回的任何内容。您的访问者甚至可以通过抛出异常来“失败”。

我几年前写了这个的第一个版本,到目前为止,它在任何情况下都对我有用。

免责声明:我只是将其拼凑在一起,质量(甚至编译)无法保证。但你明白了...:)

关于java - 使用访问者模式时是匿名还是真实的类定义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7244511/

相关文章:

Java 对 Activity 的引用

java - 更新 Java 中的属性文件

java - 按时间(频率)过滤日志消息?

ruby-on-rails - Rails 静态数据集

mysql - 如何避免每个用户的表

使用给定类型和构造函数参数创建和销毁临时对象的 C++ 函数

javascript - 如何在javascript中实现访问者模式?

java hibernate聚合错误

c# - 我将我的服务注入(inject)我的 Controller 。我应该将我的服务注入(inject)到我的 ViewModel 中吗?

c++ - 未定义对 'vtable for class' 的引用