java - java中的通用访问者模式

标签 java templates generics visitor-pattern

以下使用泛型的访问者模式的 java 实现是否足够通用、有用? (我想是的)。

可以通过某种方式改进吗?使用匿名类轻松调用非常重要。谢谢。

(使用示例):

Vector<Number> numbers = new Vector<Number>();

        numbers.add(new Double(1.2));
        numbers.add(new Float(-1.2));
        numbers.add(new Double(4.8));
        numbers.add(new Float(-3.4));
        numbers.add(new Long(123456));
        numbers.add(new Short("14"));

        For.each(numbers, new Visitor<Number>() {
            public void doIt(Double n) {
                System.out.println("doIt() for double: " + n);
            }
            public void doIt(Float n) {
                System.out.println("doIt() for float: " + n);
            }
            public void doIt(Number n) {
                System.out.println("doIt() for Number: " + n);
            }
        });

        Visitor<Number> visi =  new Visitor<Number>() {
            private StringBuffer  all = new StringBuffer ();
            public void doIt(Number n) {
                System.out.println("doIt() for Number: " + n);
                all.append(n.toString() + " ");
            }
            public Object getResult () {
                return all;
            }
        };

        For.each(numbers, visi);

        System.out.println ("all -> " + visi.getResult());

定义:

//............................................
abstract class Visitor<T> {
    public void visit(T n) {
        try {
            this.getClass().getDeclaredMethod("doIt", n.getClass()).invoke(this, n);
        } catch (Exception ex) {
            doIt((T) n);
        }
    }
    public void doIt(T n) {
        System.out.println("doIt() for base " + n);
    }
    public Object getResult() {
        return null;
    }
} // class

//............................................
class For {
    public static <T> void each (Collection<T> c, Visitor<T> f) {
        for (T v : c) {
            f.visit(v);
        }
    } // ()
} // class

最佳答案

这不是 Visitor Pattern .

访问者的特征是访问者具有 accept(Visitor v)与访问者中的访问方法交互的方法,以被访问者为参数,并针对不同类型的被访问者进行重载,形成“双重调度”机制。

引用 Design Patterns 中访客的“适用性”部分:

Use the Visitor pattern when
  • an object structure contains many classes of objects with differing interfaces, and you want to perform operations on these objects that depend on their concrete classes.
  • many distinct and unrelated operations need to be performed on objects in an object structure, and you want to avoid "polluting" their classes with these operations. Visitor lets you keep related operations together by defining them in one class. When the object structure is shared by many applications, use Visitor to put operations in just those applications that need them.
  • the classes defining the object structure rarely change, but you often want to define new operations over the structure. Changing the object structure classes requires redefining the interface to all visitors, which is potentially costly. If the object structure classes change often, then it's probably better to define the operations in those classes.

所以这个模式是为了处理多种类型对象上的类似操作。在您的示例中,您调用的访问者对象只能处理一种类型。

在修改为使用反射来处理多种类型的答案中(顺便说一句,最好将其作为对问题的编辑或作为单独的问题来完成),您将避免创建 accept(Visitor v)方法在访问的类中使用反射,这在一定程度上实现了相同的目标,但有点尴尬。我仍然拒绝称其为 Visitor 的实现。

如果您在此处编写的代码风格对您有用,请务必使用它,但请不要将其称为访问者。

这更像是 Strategy PatternFunction Object ,如果您以反射(reflect)这一点的方式重命名泛型类,那么它实际上很有用,并且您的用法类似于函数式语言中列表处理的常见模式。

我可能会对问题中的代码执行的操作是重命名您的 Visitor<T>Operation<T>并重命名您的 visit(T t)execute(T t)apply(T t) ,想到一个 Operation作为Function没有返回值。事实上,我已经以与您正在做的类似的方式使用了这一点,并使用类似的策略使用通用 Function<Domain, Range> 进行集合“映射”。对象。我不确定什么模式名称实际上适合它,但它不是 Visitor。它将函数式列表理解风格带入面向对象的世界,在这个世界中,函数并不是天然的一流对象。

关于java - java中的通用访问者模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3946408/

相关文章:

c++ - 在执行代码之前进入函数时引发异常

c# - 如何将 Func<T, object> 转换为 Func<dynamic, object>?

c# - 泛型继承 c#

java - 在运行时禁用/启用 Vaadin 8 网格的拖放支持

java - 如何跨类使用同步块(synchronized block)?

c++ - 为什么此模板签名不能用作使用引号的字符串文字?

generics - 如何强制特征的两个关联类型参数相等?

java - FitNesse 错误 : Could not find fixture

java - 如何使用 Spring REST Docs 将顶级数组记录为响应负载

c++ - 具有可变参数模板的函数对象