以下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
答案 0 :(得分:6)
这不是Visitor Pattern。
访问者的特征是被访者具有accept(Visitor v)
方法,该方法与访问者中的访问方法相互作用,以访问者为参数并为不同类型的访问者重载,形成“双重调度”机制。 / p>
从Design Patterns中的访问者的“适用性”部分引用:
使用访客模式时
- 对象结构包含许多 具有不同的对象类 接口,你想要执行 对这些对象的操作 取决于他们的具体课程。
- 需要执行许多不同且不相关的操作 对象结构中的对象,和 你想避免“污染”他们的 具有这些操作的类。 访客可让您保持相关 通过定义它们来共同操作 在一堂课。当对象 结构由许多人共享 应用程序,使用Visitor来放 只在那些应用程序中运行 需要它们。
- 定义对象结构的类很少改变,但是你 经常想要定义新的操作 在结构上。改变了 对象结构类需要 重新定义所有界面 访客,这是潜在的 昂贵。如果是对象结构 课程经常变化,然后是 可能更好地定义 这些课程的操作。
因此,这种模式用于处理多种类型对象上的类似操作。在您的示例中,您呼叫访问者的对象只能处理一种类型。
在您的答案中修改使用反射来处理多种类型(顺便说一句,这样可以更好地完成对问题的编辑或作为单独的问题),您将避免在其中创建accept(Visitor v)
方法通过使用反射来访问类,这在一定程度上实现了相同的目标,但有点笨拙。我仍然不愿称它为访客的实施。
如果您在此处撰写的样式中的代码对您有用,请务必使用它,但请不要将其称为访问者。
这更像是Strategy Pattern或Function 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);