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