【问题标题】:How to access class specific methods without instanceof or getClass如何在没有 instanceof 或 getClass 的情况下访问特定于类的方法
【发布时间】:2017-10-25 00:01:16
【问题描述】:

假设我有以下接口和实现:

interface Weapon{
    int attack();   
}

public class Sword implements Weapon {

    //Constructor, and Weapon interface implementation
    //...
    public void wipeBloodfromSword(){}
}


public class ChargeGun implements Weapon {
    //Constructor, and Weapon interface implementation  
    //...
    public void adjustlasersight(){}
}

并像这样存储它们:

List<Weapon> weaponInventory = new ArrayList<Weapon>();
weaponInventory.add(new Sword());
weaponInventory.add(new ChargeGun());

问题:

鉴于它们存储在List&lt;Weapon&gt; 中,我显然只能访问Weapon interface 中声明的方法。如果 downcastinginstanceof/getClass() 的使用应该避免,我将如何访问类特定方法 wipeBloodfromSword()adjustlasersight()?

可能的解决方案:

鉴于在调用攻击方法之前和之后都有动作,我可以像这样重写我的界面:

interface Weapon{

   //Can reload a weapon, adjust a laser sight 
   //do anything to the weapon to prepare for an attack
   void prepareWeapon(); 
   int attack();
   //Not sure of a more proper name, 
   //but you can wipe blood off sword  or take off silencer 
   void postAttackActions();
}

虽然我在控制这个爱好项目,但我可能会遇到无法更改 interface 的情况,而 interface 重写可能会解决这个特定问题,我应该怎么做如果我必须让interface 保持原样,该怎么办?

【问题讨论】:

  • “如果...我该怎么办”不是一个很好的问题类型。
  • 如果您无法更改界面,则必须使用instanceof 或反射。但正确的答案是改变你的界面。
  • 静态类不是正确答案???
  • 为什么要避免使用 instanceof?如果您将所有武器存储在列表中但想在扩展类中调用方法,则需要在尝试投射之前检查类型。否则,将每个武器子类存储在其自己的列表中(这有其自身的缺点)。或者你对武器有一个通用的方法,比如“postAttackAction”,对于剑来说,它会从剑中抹去血,而对于其他武器,它会做其他事情。或者什么都没有。您只需要围绕哪些事情是“通用的”以及哪些事情是按类处理的做出设计决策。
  • 另见:en.wikipedia.org/wiki/Chiburi“象征性地从剑刃上去除血迹的过程”:)

标签: java oop instanceof downcast


【解决方案1】:

由于您有一组固定的类,您可以使用访问者模式,该模式无需显式向下转换即可工作。

class WeaponVisitor {
   void visit(Sword aSword) { }
   void visit(ChargeGun aGun) { }
}

// add accept method to your Weapon interface
interface Weapon {
  ...
  void accept(Visitor v);
}

// then implement accept in your implementing classes
class Sword {
...
   @Override
   void accept(Visitor v) {
      v.visit(this); // this is instanceof Sword so the right visit method will be picked
   }
}

// lastly, extend Visitor and override the methods you are interested in
class OnlySwordVisitor extends Visitor {
     @Override void visit(Sword aSword) {
      System.out.println("Found a sword!");
      aSword.wipeBloodfromSword();
     }
 }

【讨论】:

  • 太好了,我不必使用downcastinginstanceofgetClass()
  • 如果可以的话,把void accept(Visitor v)改成void accept(WeaponVisitor v); 不需要OnlySwordVisitor extend Visitor,我可以直接用WeaponVisitor,对吗?
  • 是的,当然。 SwordVisitor 只是您可以用来仅对剑进行操作的访问者的一个示例。另外,如果你输入abstract class AbstractWeapon implements Weapon,你只需要在其中实现accept,如果所有具体武器都是它的子类
【解决方案2】:

您可以键入将列表项转换为 Sword 或 ChargeGun,然后调用相应的方法

((Sword) weaponInventory.get(0)).wipeBloodfromSword();

【讨论】:

  • 但是要转换,我会先检查类型(使用instanceofgetClass())。不能保证剑会成为库存中的第一个物品
猜你喜欢
  • 2016-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-07
相关资源
最近更新 更多