经常使用instanceof是好习惯吗?

Jus*_*s S 11 java instanceof hierarchy

场景.我正在写与游戏相关的代码.在那个游戏中Player(它也是一个类)有一个列表Item.还有其他类型的项继承Item,例如ContainerItem,DurableItemWeaponItem.

显然,对我来说这是非常方便的List<Item>.但是当我获得玩家物品时,我唯一的方法是通过使用instanceof关键字来区分什么类型的物品.我敢肯定,我已经读过,依赖它是不好的做法.

在这种情况下可以使用它吗?或者我应该重新考虑我的所有结构?

Mat*_*son 17

假设我正在编写一些库存代码:

public void showInventory(List<Item> items) {
    for (Item item : items) {
        if (item instanceof ContainerItem) {
            // container display logic here
        }
        else if (item instanceof WeaponItem) {
            // weapon display logic here
        }
        // etc etc
    }
}
Run Code Online (Sandbox Code Playgroud)

这将编译和工作正常.但它错过了面向对象设计的关键思想:您可以定义父类来执行一般有用的事情,并让子类填充特定的重要细节.

以上替代方法:

abstract class Item {
    // insert methods that act exactly the same for all items here

    // now define one that subclasses must fill in themselves
    public abstract void show()
}
class ContainerItem extends Item {
    @Override public void show() {
        // container display logic here instead
    }
}
class WeaponItem extends Item {
    @Override public void show() {
        // weapon display logic here instead
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们show()在库存显示逻辑的所有子类中都有一个可以查看的方法.我们如何访问它?简单!

public void showInventory(List<Item> items) {
    for (Item item : items) {
        item.show();
    }
}
Run Code Online (Sandbox Code Playgroud)

我们将所有特定于项的逻辑保留在特定的Item子类中.这使您的代码库更易于维护和扩展.它减少了第一个代码样本中长期for-each循环的认知压力.并且它准备好在show()你还没有设计过的地方重复使用.

  • 这是正确的方法,但有时还不够。以“记录”类为例-我们有2种记录-“文件”和“目录”。常用的东西可以被记录下来,但是可以说`File`具有`download()`方法。因此,除非知道文件确实是文件,否则不能从Set &lt;Record&gt;中下载文件。因此,如果遇到这种情况,多态性是不够的,但是在大多数情况下,这是最好的解决方案,因此+1是一个好的答案 (2认同)
  • 我认为向接口添加方法只是抛出`UnsupportedOperationException`是不好的设计。空对象模式的目的也完全不同。是的,它可能会完成工作,但它比区域解决方案更像是黑客。以我的“记录”示例为例。为什么要使用不适用于每条记录的方法来污染“记录”接口?通过这样做,我只会使API更加难以使用-即客户端将不得不处理愚蠢的异常或无用的返回值。 (2认同)

Sve*_*rev 5

恕我直言,使用instanceof是一种代码气味。简而言之-它使您的代码具有过程性,而不是面向对象的。OO的方式是使用访问者模式

在此处输入图片说明

访问者模式还允许您轻松构建decorators并chain of responsibility在其之上进行构建,从而实现关注点分离,从而使代码更短,更简洁,更易于阅读和测试。

还真的需要知道确切的课程吗?不能利用多态吗?毕竟Axe是一个Weapon原样Sword

  • IMO,访客模式是确保您的工作安全的好方法-其他人都无法理解您的代码! (8认同)