2015-06-20 55 views
0

我想找到一种方法来绕过使用instanceof。我创建了一个具有WeaponItem和BodyItem等多个子类的类Item。现在我想做一个诸如equip(Item)之类的调用,它应该自行确定它应该调用哪个重载函数,比如equip(BodyItem)。避免Java的实例

有没有办法绕过这种情况下使用instanceof以及你会推荐什么?我听说在大多数情况下使用instanceof是不好的做法,因此我想知道替代方案是什么。

代码:

inv.equip(it); // inv = inventory object, it = Item 

库存类中的装备功能的一个例子,说明我最好希望它

public void equip(HelmItem it) 
{ 
    if (it != this.getHelm()) 
    { 
     this.setHelm(it); 
    } 
} 

之前,我怎么过的:

public void equip(Item it) 
{ 
    if (it instanceof WeaponItem) 
    { 
     if (it != this.getWeapon()) 
     { 
      this.setWeapon((WeaponItem) it); 
     } 
    } etc for all subclasses of item 
} 
+2

查找double-dispatch和访问者模式 –

+0

[避免Java中的instanceof]可能的重复(http://stackoverflow.com/questions/15457623/avoid-instanceof-in-java) – Qiu

+1

你可以分享你的代码吗正在尝试? –

回答

3

确实,这可以通过访问者模式解决。

但是,它不一定是一个完整的访问者,而是一个简化的变体。您可以在库存传递到项目,让项目为所欲为吧:

abstract class Item { 
    public abstract void equip(Inventory inv); 
} 

class HelmItem extends Item { 
    @Override 
    public void equip(Inventory inv) { 
     inv.setHelm(this); 
    } 
} 

class WeaponItem extends Item { 
    @Override 
    public void equip(Inventory inv) { 
     inv.setWeapon(this); 
    } 
} 

然后你可以叫:

it.equip(inv) 

没有instanceof操作。

+0

这真的解决了问题!感谢您分享您的想法!它仍然相当违反直觉,因为语义上说一件物品装备了库存,但它作为解决方案起作用,所以谢谢! :D –

+0

是的,这可以通过保留'inv.equip(it)'方法来克服,但是在实现它时可以调用'it.equip(this)'。通过这种方式,您可以将物品添加到库存的集中位置,这很好,因为它符合DRY,并且您还可以在其中执行其他操作,例如计算添加的物品,检查库存是否已满等。 –

+0

虽然我们说过类似的事情,但你做得更好,并提供了一个完整的例子。 +1 – christopher

2

为什么不把方法在Item具体类,它可以装备自己?这有点直观,但它可以解决你的问题。

public class SomeConcreteItem extends Item { 
    public void equip(Body body) { 
     // Just an example. 
     body.getSections().get(0).equip(this); 
    } 
} 

这样,具体的实现知道如何装备自己和使用它的类不关心。您可以通过Item超类来引用它,并且假定Item超类有一个抽象方法public void equip(Body body);,那么您不需要知道具体实现,因此不需要instanceof运算符。

上引入一个设计模式

记下您应该谨慎引入设计模式。人们有一种不良习惯,即直接跳跃到一种复杂的模式来解决问题,当真正简单一些,并且(在我看来)更加优雅的时候。