场景。我正在写与游戏相关的代码。在该游戏中,Player
(它也是一个类)的列表为Item
。还有其他类型的项目从Item
继承,例如ContainerItem
,DurableItem
或WeaponItem
。
显然,只有List<Item>
对我来说非常方便。但是当我获得玩家物品时,我唯一的方法是使用instanceof
关键字来区分什么类型的物品。我确定我已经读过,依赖它是不好的做法。
在这种情况下可以使用吗?或者我应该重新考虑我的所有结构?
答案 0 :(得分:15)
假设我正在编写一些库存代码:
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
}
}
那将编译并正常工作。但它错过了面向对象设计的关键思想:您可以定义父类来执行一般有用的事情,并让子类填写特定的重要细节。
上述替代方法:
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<Item> items) {
for (Item item : items) {
item.show();
}
}
我们将所有特定于项的逻辑保留在特定的Item子类中。这使您的代码库更易于维护和扩展。它减少了第一个代码样本中长期for-each循环的认知压力。它准备好show()
可以在你还没有设计过的地方重复使用。
答案 1 :(得分:3)
使用instanceof
的恕我直言是一种代码气味。简单地说 - 它使您的代码程序化,而不是面向对象。 OO方式是使用visitor pattern。
访问者模式还允许您轻松地在其上构建decorator
和chain of responsibility
,从而实现关注点分离,从而使代码更简洁,更易于阅读和测试。< / p>
你真的还需要知道确切的课程吗?你不能利用多态性吗?毕竟Axe
是一个Weapon
,就像Sword
一样。
答案 2 :(得分:3)
您应该重新思考并尝试使用多态来实现您的import Z.A.file1
print(file1.TMP_DATA_FILE)
想法。
以下是您的问题的一些参考资料,可能有所帮助:
答案 3 :(得分:2)
您应该重新考虑您的结构,非元代码中的instanceof
几乎总是反模式的标志。尝试在Item
- 类/接口中定义所有Item
共有的行为(例如,在点击它们时有图片,描述和发生的事情),使用{{ 1}} - 关键字if appropiate,然后使用polymorphism来实现细节。
答案 4 :(得分:0)
如果您理解它很容易就可以了。
将分支逻辑从它们自然所属的地方移动到子类并不一定是个好主意。它可能会造成错误的依赖;它可能会导致臃肿的课程,并且可能很难导航和理解。
最后,关于如何在一维空间中以多维度关注物理组织我们的代码。这不是一个微不足道的问题,它是主观的,没有灵丹妙药。
特别是,我们的行业继承了上个世纪基于那个时代的技术和经济约束而制定的许多规则。例如,工具非常有限;程序员非常昂贵;应用程序发展缓慢。
其中一些规则今天可能不再适用。
答案 5 :(得分:0)
我不一定认为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);
}
}