java中的通用访客模式

时间:2010-10-15 21:49:15

标签: java templates generics visitor

以下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

3 个答案:

答案 0 :(得分:6)

这不是Visitor Pattern

访问者的特征是被访者具有accept(Visitor v)方法,该方法与访问者中的访问方法相互作用,以访问者为参数并为不同类型的访问者重载,形成“双重调度”机制。 / p>

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

 使用访客模式时
     
  •    对象结构包含许多    具有不同的对象类    接口,你想要执行    对这些对象的操作    取决于他们的具体课程。  
  •  
  •    需要执行许多不同且不相关的操作    对象结构中的对象,和    你想避免“污染”他们的    具有这些操作的类。    访客可让您保持相关    通过定义它们来共同操作    在一堂课。当对象    结构由许多人共享    应用程序,使用Visitor来放    只在那些应用程序中运行    需要它们。  
  •  
  •    定义对象结构的类很少改变,但是你    经常想要定义新的操作    在结构上。改变了    对象结构类需要    重新定义所有界面    访客,这是潜在的    昂贵。如果是对象结构    课程经常变化,然后是    可能更好地定义    这些课程的操作。    
  •   

因此,这种模式用于处理多种类型对象上的类似操作。在您的示例中,您呼叫访问者的对象只能处理一种类型。

在您的答案中修改使用反射来处理多种类型(顺便说一句,这样可以更好地完成对问题的编辑或作为单独的问题),您将避免在其中创建accept(Visitor v)方法通过使用反射来访问类,这在一定程度上实现了相同的目标,但有点笨拙。我仍然不愿称它为访客的实施。

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

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

我可能会对问题中的代码执行的操作是将您的Visitor<T>重命名为Operation<T>,并将您的visit(T t)重命名为execute(T t)apply(T t)Operation的{​​{1}}没有返回值。事实上,我使用的方式与您正在使用的方式类似,并使用类似的策略来使用通用Function对象进行集合“映射”。我不确定哪个模式名称实际适合它,但它不是访客。它将功能列表理解风格带入了OO世界,其中函数不是天生的一流对象。

答案 1 :(得分:2)

感谢donroby关于我的初始代码没有实现访问者模式的答案,我来到这个新版本。

我想它现在实现了访问者模式,而不需要使用accept()方法修改被访问元素。无论如何,它能够根据元素类型调用正确的方法(我猜这是accept()的任务),感谢反思。

首先,使用的一个例子:

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

产生此输出

doIt() for double: 1.2
doIt() for float: -1.2
doIt() for double: 4.8
doIt() for float: -3.4
doIt() for Number: 123456
doIt() for Number: 14

最后是代码

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 For {
public static <T> void each (Collection<T> c, Visitor<T> f) {
    for (T v : c) {
        f.visit(v);
    }
} // ()

}

答案 2 :(得分:0)

怎么样

    for(String s : words)
        System.out.println (s.toUpperCase());

    int total = 0;
    for(String s : words)
        total = total + s.length();
    System.out.println (" sum of lengths = " + total);