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

时间:2021-10-04 16:10:14

The scenario. I'm writting game-related code. In that game a Player(its also a class) has a list of Item. There are other types of items that inherit from Item, for example ContainerItem, DurableItem or WeaponItem.

场景。我正在写与游戏相关的代码。在那个游戏中,玩家(它也是一个类)有一个Item列表。还有其他类型的项从Item继承,例如ContainerItem,DurableItem或WeaponItem。

Obviously it is very conveniant for me to just have List<Item>. But when I get the players items, the only way for me to distinguish between what type of item is by using the instanceof keyword. I'm sure I've read that reliaing on it is bad practice.

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

Is it ok to use it in this case? Or should I rethink all of my structure?

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

6 个解决方案

#1


11  

Let's say I am writing some inventory code:

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

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

That will compile and work just fine. But it misses out on a key idea of object oriented design: You can define parent classes to do general useful things, and have child classes fill in specific, important details.

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

Alternate approach to above:

上面的替代方法:

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

Now we have one place to look, the show() method, in all our child classes for inventory display logic. How do we access it? Easy!

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

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

We are keeping all the item-specific logic inside specific Item subclasses. This makes your codebase easier to maintain and extend. It reduces the cognitive strain of the long for-each loop in the first code sample. And it readies show() to be reusable in places you haven't even designed yet.

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

#2


3  

You should rethink maybe and try to use polymorphism to implement your List<Item> idea.

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

Here is some references for your problem that can probably help :

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


(References from Is instanceof considered bad practice? If so, under what circumstances is instanceof still preferable? )

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

#3


2  

IMHO using instanceof is a code smell. Simply put - it makes your code procedural, not object oriented. The OO way of doing this is using the visitor pattern.

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

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

The visitor pattern also allows you to easily build decorators and chain of responsibility on top of it, thus achieving separation of concerns, which results in shorter, cleaner and easier to read and test code.

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

Also do you really need to know the exact class ? Cant you take advantage of polymorphism ? After all Axe IS a Weapon just as Sword is.

你真的需要知道确切的课程吗?你不能利用多态性吗?毕竟Axe就像剑一样是武器。

#4


2  

You should rethink your structure, instanceof in non-meta code is almost always a sign for an anti-pattern. Try to define the behaviour all Items have in common (like having a picture, a description and something happening when you click on them) in the Item-class/interface, making use of the abstract-keyword if appropiate, and then use polymorphism to implement the specifics.

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

#5


0  

It's ok if it's easy for you to understand.

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

Moving branching logics from where they naturally belong all to subclasses is not necessarily a good idea. It may create the wrong dependency; it may cause bloated classes, and it may be hard to navigate and understand.

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

In the end, it's all about how to physically organize our code with multiple dimensions of concerns in a one dimensional space. It's not a trivial problem, it is subjective, and there is no panacea.

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

In particular, our industry inherited a lot of rules of thumbs that were made in the last century based on technical and economical constraints of that era. For example, tooling were very limited; programmers were highly expensive; applications evolved slowly.

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

Some of these rules may no longer apply today.

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

#6


0  

I don't necessarily think instanceof is bad for coders who know what they are doing and use it to avoid having to write more complicated code to get around it. There is a use for everything, and also a mis-use.

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

With that said, the description you provide does not require instanceof. There are various ways you can implement this without instanceof, and (the most important thing) the alternate solution must be better than using instanceof. Don't just go with a non-instanceof solution to avoid instanceof because you heard it is bad.

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

I think that for your scenario an non-instanceof solution has benefits in making the solution more easily extensible.

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

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

}

or

要么

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

}

#1


11  

Let's say I am writing some inventory code:

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

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

That will compile and work just fine. But it misses out on a key idea of object oriented design: You can define parent classes to do general useful things, and have child classes fill in specific, important details.

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

Alternate approach to above:

上面的替代方法:

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

Now we have one place to look, the show() method, in all our child classes for inventory display logic. How do we access it? Easy!

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

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

We are keeping all the item-specific logic inside specific Item subclasses. This makes your codebase easier to maintain and extend. It reduces the cognitive strain of the long for-each loop in the first code sample. And it readies show() to be reusable in places you haven't even designed yet.

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

#2


3  

You should rethink maybe and try to use polymorphism to implement your List<Item> idea.

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

Here is some references for your problem that can probably help :

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


(References from Is instanceof considered bad practice? If so, under what circumstances is instanceof still preferable? )

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

#3


2  

IMHO using instanceof is a code smell. Simply put - it makes your code procedural, not object oriented. The OO way of doing this is using the visitor pattern.

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

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

The visitor pattern also allows you to easily build decorators and chain of responsibility on top of it, thus achieving separation of concerns, which results in shorter, cleaner and easier to read and test code.

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

Also do you really need to know the exact class ? Cant you take advantage of polymorphism ? After all Axe IS a Weapon just as Sword is.

你真的需要知道确切的课程吗?你不能利用多态性吗?毕竟Axe就像剑一样是武器。

#4


2  

You should rethink your structure, instanceof in non-meta code is almost always a sign for an anti-pattern. Try to define the behaviour all Items have in common (like having a picture, a description and something happening when you click on them) in the Item-class/interface, making use of the abstract-keyword if appropiate, and then use polymorphism to implement the specifics.

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

#5


0  

It's ok if it's easy for you to understand.

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

Moving branching logics from where they naturally belong all to subclasses is not necessarily a good idea. It may create the wrong dependency; it may cause bloated classes, and it may be hard to navigate and understand.

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

In the end, it's all about how to physically organize our code with multiple dimensions of concerns in a one dimensional space. It's not a trivial problem, it is subjective, and there is no panacea.

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

In particular, our industry inherited a lot of rules of thumbs that were made in the last century based on technical and economical constraints of that era. For example, tooling were very limited; programmers were highly expensive; applications evolved slowly.

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

Some of these rules may no longer apply today.

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

#6


0  

I don't necessarily think instanceof is bad for coders who know what they are doing and use it to avoid having to write more complicated code to get around it. There is a use for everything, and also a mis-use.

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

With that said, the description you provide does not require instanceof. There are various ways you can implement this without instanceof, and (the most important thing) the alternate solution must be better than using instanceof. Don't just go with a non-instanceof solution to avoid instanceof because you heard it is bad.

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

I think that for your scenario an non-instanceof solution has benefits in making the solution more easily extensible.

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

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

}

or

要么

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

}