我目前正在实现一个函数,使用超类作为参数。
例如:
private void foo(Parent parent) {
if(parent.getClass() == Child1.class) {
Child1 c1 = (Child1) parent;
System.out.println(c1.getChild1Attribute());
}
else if(parent.getClass() == Child2.class) {
Child2 c2 = (Child2) parent;
System.out.println(c1.getChild2Attribute());
}
else if(parent.getClass() == Parent.class) {
System.out.println(parent.getParentAttribute());
}
}
这是个坏主意吗?
我在这里阅读了一些帖子,说使用getClass()
或instanceof
设计不好:
答案 0 :(得分:7)
这不一定是一个糟糕的设计,但它表明可能会发生错误。
您的具体案例看起来很糟糕,因为看起来单个方法可以识别多个类。这可能表明您错过了过载的可能性,或者有机会使用多种调度模式之一:
// Three overloads - one per target class
private void foo(Parent obj) {
}
private void foo(Child1 obj) {
}
private void foo(Child2 obj) {
}
常见的多个调度模式之一是visitor pattern,看看它是否适用于您正在解决的问题。
答案 1 :(得分:6)
是的,这是糟糕的设计。
相反,您应该在超类中创建一个抽象方法,并在每个子类中覆盖它以执行所需的操作。
答案 2 :(得分:2)
是的,这是糟糕设计的标志。这将处理不同类的复杂性放在一个类中,而不是将相关知识封装在适当的类本身中。当您向层次结构中添加更多类时,这会受到伤害,因为编译器不会提醒您实现foo
的相关新功能。
更好的版本是
private void foo(Parent parent){
System.out.println(parent.getFooParentAttribute());
}
然后在每个类上实现getFooParentAttribute
。
答案 3 :(得分:1)
首选instanceof
方法
我赞成instanceof方法的原因是当你使用getClass方法时,你有一个限制,即对象只等于同一个类的其他对象,相同的运行时类型。
答案 4 :(得分:0)
您的方法存在两个问题。首先,假设您添加了Parent
,Child3
的新子类。任何情况都不会涵盖这一点,因此它根本不打印任何内容。如果您添加了Child1
,ChildOfChild1
的新子类,则同样如此。这也不会被涵盖。
如果您使用的是instanceof
,则ChildOfChild1
将显示为Child1
的实例,Child3
将是Parent
的实例。
但一般来说,你想要完全避免这种模式的原因是所有这些情况都令人惊讶。通常更好的是写
void foo(Parent p) {...}
并将通用代码放在那里,然后对于任何特殊情况,创建一个
void foo(Child1 c) {...}
这使得更清楚的是发生了什么:如果你看到这两种方法,你知道Child1
(和它的子类)有一些特殊的套管代码,而Parent
和任何其他子所有课程都以同样的方式对待。