经常使用instanceof是一种好习惯吗?

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

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

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

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

 public void showInventory(List items) { for (Item item : items) { if (item instanceof ContainerItem) { // container display logic here } else if (item instanceof WeaponItem) { // weapon display logic here } // etc etc } } 

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

上面的替代方法:

 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 } } 

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

 public void showInventory(List items) { for (Item item : items) { item.show(); } } 

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

您应该重新思考并尝试使用多态来实现List想法。

以下是您的问题的一些参考,可能会有所帮助:

  • 优先于实例和向下转换的多态性
  • instanceof与getClass in equals方法(采访Josh Bloch)
  • 多态性和接口 (请参阅有关何时使用instanceof的部分)

(参考来自Is instanceof被认为是不好的做法?如果是,在什么情况下仍然更可取? )

使用instanceof恕我直言是一种代码气味。 简单地说 – 它使您的代码程序化,而不是面向对象。 OO方式是使用访问者模式 。

在此处输入图像描述

访问者模式还允许您轻松地在其上构建decoratorchain of responsibility ,从而实现关注点的分离,从而使代码更短,更清晰,更易于阅读和测试。

真的需要知道确切的课程吗? 你不能利用多态性吗? 毕竟Axe就像SwordWeapon

你应该重新考虑你的结构,非元代码中的instanceof几乎总是反模式的标志。 尝试在Item -class / interface中定义所有Item共有的行为(比如有一张图片,一个描述和点击它们时发生的事情),如果适当的话,使用abstract -keyword,然后使用多态实施细节。

如果你很容易理解它就没关系。

将分支逻辑从它们自然所属的位置移动到子类并不一定是个好主意。 它可能会造成错误的依赖; 它可能会导致臃肿的类,并且可能很难导航和理解。

最后,关于如何在一维空间中物理组织具有多维关注维度的代码。 这不是一个微不足道的问题,它是主观的,并没有灵丹妙药。

特别是,我们的行业inheritance了上个世纪基于那个时代的技术和经济约束而制造的许多规则。 例如,工具非常有限; 程序员非常昂贵; 应用程序发展缓慢。

其中一些规则今天可能不再适用。

我不一定认为instanceof对于知道他们正在做什么的编码员是不利的,并且使用它来避免编写更复杂的代码来绕过它。 一切都有用,也有误用。

话虽如此,您提供的描述不需要instanceof。 有多种方法可以在没有instanceof的情况下实现这一点,而且(最重要的是)备用解决方案必须比使用instanceof更好。 不要只使用非实例解决方案来避免instanceof,因为你听说它很糟糕。

我认为,对于您的场景,非实例解决方案可以使解决方案更易于扩展。

 for (Item i: items) { if (ItemTypes.WEAPON_ITEM.equals(i.getType)) { processWeaponType(i); } } 

要么

 for (Item i: items) { if (WeaponItem.class.equals(i.getType)) { processWeaponType(i); } }