java中的虚拟方法问题
简单地说:我希望以下代码打印“sub”: 我不想改变打印(元素e)。所以一点也不像java中的虚拟方法问题,java,casting,virtual-functions,visitor,Java,Casting,Virtual Functions,Visitor,简单地说:我希望以下代码打印“sub”: 我不想改变打印(元素e)。所以一点也不像 private static void print(Element e) { if (e instanceof SubElement) { print((SubElement) e); } else { System.out.println("e"); } } 我想做的是 print(e.getClass().cast(e)); 自动将其转换为真正的子类
private static void print(Element e) {
if (e instanceof SubElement) {
print((SubElement) e);
} else {
System.out.println("e");
}
}
我想做的是
print(e.getClass().cast(e));
自动将其转换为真正的子类,并强制系统输入print(子元素e)。这可能吗?是的。你可以用。但是,它适用于已建立的定义良好的层次结构,因为您必须定义的访问者界面需要针对每种类型的方法
interface ElementVisitor {
visit(Element e);
visit(SubElement se);
}
class ElementerPrinter implements ElementVisitor {
visit(Element e) { System.out.println("e"); }
visit(SubElement e) { System.out.println("sub"); }
}
class Element {
// here's the trick, Element knows that this is Element
// and childs have to implement it!
// if the parent-most class is an interface it force you to implement!
accept(ElementVisitor visitor) { visitor.visit(this); }
}
class SubElement {
// here's the trick, Element knows that this is SubElement
accept(ElementVisitor visitor) { visitor.visit(this); }
}
print()
确实需要成为元素的实例方法。否则,您正试图以一种艰难的方式模拟多态性。如果您希望这样做,就不能真正避免从Class
映射到函数对象的一系列If
语句。何必麻烦?在编译时选择运行的重载方法,因此选择元素版本而不是子元素版本。更合乎逻辑的是让元素或子类包含应该打印的数据
class Element {
public String getName() {
return "e";
}
}
class SubElement extends Element {
public String getName() {
return "sub";
}
}
然后在打印方法中:
private static void print(Element e) {
System.out.println(e.getName());
}
这是否有意义将取决于元素
类实际上是什么以及打印的数据代表什么。您是否能够将行为的差异推到元素类中
Element e = new SubElement();
print(e);
...
private static void print(Element e) {
System.out.println(e.getMessageToPrint());
}
// no longer needed
//
//private static void print(SubElement e) {
// System.out.println("sub");
//}
这样,SubElement
就可以重写getMessageTopPrint()
方法
或者更好:
Element e = new SubElement();
e.print();
我会选择不同的方法。或者
按照其他人的建议使用多态性,扩展元素以添加print()方法(可以被子类覆盖)或
定义助手界面并结合使用策略和工厂模式:
基类
public class Element{}
public class SubElement extends Element{}
public interface PrintHelper{
void print(Element element);
}
派生类
public class Element{}
public class SubElement extends Element{}
public interface PrintHelper{
void print(Element element);
}
打印元素的辅助界面
public class Element{}
public class SubElement extends Element{}
public interface PrintHelper{
void print(Element element);
}
工厂为给定元素获取最佳PrintHelper
public class PrintHelperFactory{
private final Map<Class<? extends Element>, PrintHelper> registeredHelpers =
new HashMap<Class<? extends Element>, PrintHelper>();
// Register a PrintHelper for a given Element class.
public void registerHelper(final Class<? extends Element> clazz,
final PrintHelper helper){
this.registeredHelpers.put(clazz, helper);
}
// Get the most specific PrintHelper for a given Element.
public PrintHelper getHelperForElement(final Element element){
Class<? extends Element> clazz = element.getClass();
while(!Object.class.equals(clazz)){
if(this.registeredHelpers.containsKey(clazz)){
return this.registeredHelpers.get(clazz);
}
clazz = (Class<? extends Element>) clazz.getSuperclass();
}
return null;
}
}
Element
Sub Element
输出
public class PrintHelperFactory{
private final Map<Class<? extends Element>, PrintHelper> registeredHelpers =
new HashMap<Class<? extends Element>, PrintHelper>();
// Register a PrintHelper for a given Element class.
public void registerHelper(final Class<? extends Element> clazz,
final PrintHelper helper){
this.registeredHelpers.put(clazz, helper);
}
// Get the most specific PrintHelper for a given Element.
public PrintHelper getHelperForElement(final Element element){
Class<? extends Element> clazz = element.getClass();
while(!Object.class.equals(clazz)){
if(this.registeredHelpers.containsKey(clazz)){
return this.registeredHelpers.get(clazz);
}
clazz = (Class<? extends Element>) clazz.getSuperclass();
}
return null;
}
}
Element
Sub Element
也许这只是一个简单的例子。但是如果是这种情况,我应该执行一个多态元素.getMyString()方法,并且只让print方法知道System.out.if事实上,通过他的第二个示例(cast),我怀疑他试图执行双重分派(不仅通过变量类型匹配正确的方法,而且还通过具体的保持实例匹配正确的方法)。访问者模式就是这样存在的。实际上,我正在尝试根据我的需要更改访问者模式;)我有一个不能更改的访问者界面,因此如果我必须向系统添加新的子类,我看不到任何方法可以单独处理新的子类,而不使用原始visit(元素e)方法中的instanceof。我希望有一种方法可以强制系统自动使用正确的方法,而无需向访问者界面添加代码。当您对元素进行子类化时,子元素类可以重写accept方法来调用visit(子元素)。当然,已经存在的访问者没有这个方法。您可以执行ExtendedVisitor,如果(ExtendedVisitor的访问者实例)((ExtendedVisitor)访问者),则接受应该执行if代码>附言:没那么好。但它可以工作,并且与已经存在的accept调用很好地集成。如果你从头开始做这件事,也许地图会更好。好的,谢谢你提供的信息,我仍然希望找到一种方法,使用反射API自动调用正确的方法,如果它可以避免子类中的这种检查,但是我现在还没有让它工作。+1首先描述问题,然后描述一个解决方案。如果你有一个静态方法,它将一个或多个对象作为一个参数,那么你应该考虑使该方法成为一个实例方法。这简化了您的代码,并且很可能简化了您的逻辑。静态方法最适合用于原语和不能更改的类,如字符串或字节[]。