java中的通用访客模式

以下java实现的访问者模式使用generics,一般是否有用? (我想是的)。

它能以某种方式得到改善吗? 使用匿名类轻松调用很重要。 谢谢。

(使用示例):

Vector numbers = new Vector(); 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() { 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 visi = new Visitor() { 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 { 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  void each (Collection c, Visitor f) { for (T v : c) { f.visit(v); } } // () } // class 

这不是访客模式 。

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

引用“ 设计模式中的访客”的“适用性”部分:

使用访客模式时

  • 对象结构包含许多具有不同接口的对象类,并且您希望对依赖于其具体类的这些对象执行操作。
  • 需要对对象结构中的对象执行许多不同且不相关的操作,并且您希望避免使用这些操作“污染”它们的类。 访问者允许您通过在一个类中定义它们来保持相关操作。 当许多应用程序共享对象结构时,使用Visitor将操作放在那些需要它们的应用程序中。
  • 定义对象结构的类很少改变,但是您经常希望在结构上定义新的操作。 更改对象结构类需要重新定义所有访问者的界面,这可能是昂贵的。 如果对象结构类经常更改,那么在这些类中定义操作可能更好。

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

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

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

这更像是一个策略模式或一个函数对象 ,如果你以反映它的方式重命名generics类,它实际上是有用的,你的用法类似于函数式语言中列表处理的常见模式。

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

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

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

首先,使用示例:

 Vector numbers = new Vector(); 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() { 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(): -  1.2
 doIt()for double:4.8
浮动的doIt(): -  3.4
 doIt()编号:123456
 doIt()for Number:14

最后是代码

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

}

怎么样

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