簡體   English   中英

如何檢查哪個子類被傳遞給構造函數?

[英]How do I check which subclass was passed into a constructor?

我對 Java 和編程比較陌生,所以如果這個問題看起來很愚蠢,我深表歉意。 我正在為 Java 編程類創建一個戰斗游戲——我有一個帶有一些基本方法的 Hero 類和一個擴展 Hero 但添加了自己獨特方法的子類 Paladin。我想要一個 Battleground 對象,它可以傳入 ANY Hero 類,然后檢查傳入的是哪個特定子類。如何確定傳入的是哪個 Hero 子類?

public class Hero {

  private String name;
  private int hitPoints;

  public Hero (String name, int hitPoints) {
     this.name = name;
     this.hitPoints = hitPoints;
  }

  public String getName() { return this.name; }

  public int getHitPoints() { return this.hitPoints; }

  public void takeDamage(int amount) { this.hitPoints -= amount; }
}

這是聖騎士班

public class Paladin extends Hero {

  public Hero (String name, int hitPoints) {
    super(name, hitPoints);
  }

  public void heal(int amount) {
    this.hitPoints += amount;
  }
}

所以在戰場類中,我有一個方法嘗試(錯誤地)檢查傳入的英雄是否是聖騎士。 我該怎么做呢? if 語句是一個占位符偽代碼,只是為了闡明我的意思。

public class Battleground {

  private Hero player;

  public Battleground (Hero player) {
    this.player = player;
  }

  public void startRound() {
    // HERE!!
    if (player.equals(Paladin)) {
      player.heal();
    }
  }
}

考慮到您的職業實際建模的內容,對於戰場來說,知道聖騎士在回合開始時會自我治療並沒有多大意義,戰場也沒有責任確保聖騎士自我治療。

一個更明智的設計是讓游戲通知英雄回合已經開始,並讓特定的Hero子類控制該回合開始時那種英雄的行為。 例如:

public class Hero {
    // ...

    public void onRoundStart() {
        // do nothing
    }
}
public class Paladin extends Hero {
    // ...

    @Override
    public void onRoundStart() {
        // your heal method takes an int as its argument
        heal(10);
    }
}
public class Battleground {
    // ...

    public void startRound() {
        // let the particular Hero subclass control what happens
        player.onRoundStart();

        // ...
    }
}

這樣你就不需要任何if語句或instanceof檢查,而且定義 Paladin 行為的代碼也在它合理所屬的Paladin類中。 如果以后想更改聖騎士的規則,更容易知道需要編輯哪個職業。

這種重構被稱為“ 用多態替換條件”。

使用 Instanceof 有時被認為是一種代碼味道

使用 instanceof 可以被認為是一種代碼異味——這意味着一種不好的做法。 有一個替代方案供您考慮。

heal()方法添加到Hero類,但將實現留空。

Paladin類中只放置一個實現。 然后,即使所有玩家都會調用heal() ,它只會在Paladins內部執行某些操作。

但是...如果您仍然需要檢測類類型...

檢測類的方法

有多種方法可以區分類別。 實例為一。 另一個是有不同的構造函數。 第三個是有一個名為 EntityType 的 ENUM 或 String 字段。

在您的情況下,我認為instanceof或使用special field最有意義。

實例

if(player instanceof Paladin)

使用特殊字段

快速示例英雄

 public class Hero {

      private String name;
      private int hitPoints;
      private int HeroType;

     public Hero (String name, int hitPoints) {
          this.name = name;
          this.hitPoints = hitPoints;
          this.heroType = BASIC_HERO;
      }       

      public static int BASIC_HERO = 0;
      public static int PALADIN_HERO = 1;

... }

快速示例聖騎士

public class Paladin extends Hero {

public Paladin(String name, int hitPoints) {
    super(name, hitPoints);
    this.heroType = PALADIN_HERO;
  }

}

檢測類型

您將在兩個類中都有一個名為getHeroType()

if(hero.getHeroType == Hero.PALADIN_HERO){

}else if(hero.getHeroType == Hero.BASIC_HERO){

}

如果需要,您可以使用來檢查對象的類:

if (player instanceof Paladin)

毫無疑問,這會奏效。 如果您沒有很多“特殊”行為和有限的少量案例,那可能是一個合理的解決方案。 但是假設你的游戲最終會對Hero每個子類進行很多特殊處理,而且可能不僅僅是在你的Battlefield類的startRound()方法中,你的代碼有一天會被這些instanceof檢查startRound()混亂。 同樣適用,如果您在Hero類中使用特定類型字段。

在這種情況下,更好的解決方案可能是將邏輯重新定位到特殊類中,並在可能的情況下盡量避免類型檢查,或者至少在必要時為它們提供一個明確定義的位置。

更新:刪除了錯誤的演示實現

你總是可以做player.getClass來獲得實際的類。 至於if語句,您可以使用instanceof運算符。

所以

if (player instanceof Paladin) {
  ((Paladin)player).heal();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM