如果应该避免向下转型,那我该怎么办?

4

有以下接口类:

public interface IGameObject {

    String gameObjectID();
    String gameObjectName();
    void isActionValid(String action);
    void viewActions();
}

我有一个抽象类,实现了上述接口。
package gameprobjectpackage;

public abstract class Weapon implements IGameObject {
//Left out getters/setters to keep it simple
private String gameOjectID;
private String gameObjectName;
private int damage;

public Weapon(String gameOjectID, String gameObjectName,int damage) {
    super();
    this.gameOjectID = gameOjectID;
    this.gameObjectName = gameObjectName;
    this.damage = damage;
}

我看到一些帖子建议避免向下转型。我理解其中的原因,但是我的问题是如果我需要访问一个特定于子类的方法怎么办。例如:

public class ChargeGun extends Weapon {


private String [] chargeGunActions;

public ChargeGun(String gameOjectID, String gameObjectName, int damage) {
    super(gameOjectID, gameObjectName, damage);

        chargeGunActions = new String [3];
        chargeGunActions[0] = "Charge and Fire";
        chargeGunActions[1] = "Release";
        chargeGunActions[2] = "Drop Gun";
}

//This method is only meant for gun, and this type of gun is the only one in my game.  
//This method, I don't belive should be in the abstract method weapon, because NOT every weapon is a gun.

public void reloadGun()
{

}

我将其存储在一个库存哈希表中,如下所示:

Map<String,IGameObject> inventory = new HashMap<String,IGameObject>();

当我检索它时,我会得到一个 IGameObject ,如何正确地转换它,以便我可以访问ChargeGun中的方法?


我没有看到其他不使用向下转换的方法。你可以将它伪装成其他东西,比如创建一个InventoryMap类,该类具有检索特定类型地图或已经向下转换的对象的方法,或许可以使你的代码更加简洁。但在底层仍然是向下转换。 - Paulo Avelar
谢谢,只是出于好奇,我该如何清理它? - user6162113
你可能应该拆分你的库存,因为其他物品如消耗品等都有不同的特定类方法。 - Murat Karagöz
@Nexusfactor 实现一个 InventoryMap 类,并添加一个 #getItems(Class<?> clazz) 方法,这样你就可以通过调用 inventory.getItems(ChargeGun.class) 来检索一个 Map<ChargeGun>。有了新创建的枪支映射表,你可以随心所欲地进行操作。向下转型将在 getItems() 方法内部发生。只有当你计划一次性处理同一类对象时,才有意义。否则,请实现特定的获取器,例如 #getGun(String key)。但是请注意,如果键匹配的对象不是枪支,则要小心所需的行为。 - Paulo Avelar
1个回答

6
您可以使用访问者模式,它可以使您免于强制转换。其思想很简单:您拥有一个IGameObject清单,其中将具有一个accept(GameObjectVisitor v)方法,该方法直接调用v.visit(this)。在GameObjectVisitor中,您只需为每个实现实现visit方法:例如visit(Chargegun g),visit(Sword s)等。
换句话说,这就像回旋镖的原理:GameObjectVisitor调用item.accept(this),并且Item实现accept(GameObjectVisitor g)与简单的g.visit(this)。
通过这样做,访问者对于每个实现都有多个visit方法,并且可以执行特定的操作,而无需进行强制转换/使用instanceof。

使用这个模式,我还能访问只有ChargeGun可用的方法——reload方法吗? - user6162113
是的,因为在您在IGameObjectVisitor中声明的visit(ChargeGun chargeGun)中,您将参数声明为ChargeGun,因此所有特定方法都可用。 - Jonathan Schoreels

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接