使用.getClass()被认为是一种不好的设计吗?

4

我正在实现一个函数,并且将超类作为参数。

例如:

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 是不好的设计:


如果有更好的选择,那么使用不良设计是不明智的。但有时候你没有更好的选择。如果可能的话,应该使用本地的Java方法分派而不是if-instanceof习惯用法。 - Marko Topolnik
是的,一般来说这是不好的面向对象设计。 - leonbloy
这并不一定是坏事,但你为什么想要这样做呢? - 0x6C38
5个回答

7

这并不一定是一个糟糕的设计,但它暗示着可能出现了问题。

你的特殊情况看起来很糟糕,因为一个方法似乎意识到多个类。这可能表明你错过了一个重载的可能性,或者你有机会使用多次分派模式之一:

// Three overloads - one per target class
private void foo(Parent obj) {
}
private void foo(Child1 obj) {
}
private void foo(Child2 obj) {
}

其中一种常见的多分派模式是访问者模式,请查看它是否适用于您正在解决的问题。


这只是语法糖;基本设计仍然相同,了解foo如何响应各种参数类别的知识仍在单个类中。它还需要重复使用System.out.println调用。 - Fred Foo
@larsmans 知道如何响应各种参数类并不是一种糟糕的设计,只要您知道您已经覆盖了它们所有。任何实现访问者模式的人都知道这一点:):):) - Sergey Kalinichenko

6

是的,这是一个糟糕的设计。

相反,你应该在超类中创建一个单一的抽象方法,并在每个子类中重写它以执行所需的操作。


2

是的,这是设计不好的迹象。这样做将不同类的复杂性放在一个类中处理,而不是将相关知识封装在适当的类本身中。当你添加更多类到你的层次结构中时,这会造成困扰,因为编译器不会提醒你为foo实现相关的新功能。

更好的版本应该是

private void foo(Parent parent){
    System.out.println(parent.getFooParentAttribute());
}

然后在每个类上实现getFooParentAttribute

1

更喜欢使用 instanceof 方法

Josh Bloch on Design

我更喜欢使用 instanceof 方法的原因是,当您使用 getClass 方法时,您会受到限制,即对象仅等于相同类别、相同运行时类型的其他对象。


即使如此,“instanceof”也表示设计不良。(我知道你需要它用于“equals(Object)”) - Tom Hawtin - tackline
@TomHawtin-tackline 谢谢您纠正我。请问您是如何做到的? - Suresh Atta

0

你的方法存在两个问题。首先,假设你添加了一个新的Parent子类Child3,这不包含在任何一个case中,所以它什么也不打印。如果你添加了一个Child1的子类ChildOfChild1,同样也不会被覆盖。

如果你使用instanceof,那么ChildOfChild1将出现为Child1的实例,而Child3将是Parent的实例。

但一般来说,你要避免这种模式的原因是所有这些情况都可能令人惊讶。通常更好的方法是编写

void foo(Parent p) {...}

在那里放入通用代码,然后对于任何特殊情况,创建一个

void foo(Child1 c) {...}

这使得发生的事情更清晰:如果您看到那两种方法,您就知道Child1(以及其子类)有一些特殊情况的代码,而Parent和任何其他子类都被同样对待。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接