如何为两个不同的子类创建超类

How can I create a SuperClass for two different SubClasses

想象一下这样的事情: 我有两个 类: 节点A和节点B。 NodeA 存储一个 Integer 并有一个 getter 方法。 NodeB 没有。

现在我想创建一个超类节点, 可以调用 getter-方法。 但是我不希望 NodeB 存储整数。 我该如何处理?

使用下面的代码, NodeB 抛出异常。 超类 Node 有一个 Optinal.

public abstract class Node {
    public Integer getValue();
}

public class NodeA extends Node {

    public Integer value;

    public NodeA() {}

    @Override   
    public Integer getValue() {
        return this.value;
    }
}

public class NodeB extends Node {

    public NodeB() {}

    @Override   
    public Integer getValue() {
        throw new Exception();
    }
}

编辑:在此处添加以下虚假答案的解释。

我的工作是制作纸牌游戏。我有 NormalCards 和 Jokers。 NormalCards 有一个 Value,而 Jokes 没有。我想要一个超类的原因是我可以创建一个列表

假设您想遍历列表并对所有值求和。

由于 Jokes 没有值,我必须检查 Card 是否是 Joker。如果不将其转换为 NormalCard 并获取值。 e 我的老师说,演员表是邪恶的....所以我正在寻找替代方案。

简短的回答是:你不知道。

稍微长一点的回答:如果你觉得有必要这样做,你应该改进你的设计。这违反了 OO 设计原则,尤其是 LSP.

只是成像有这样的方法:

void printValue(Node node) {
   System.out.println(node.getValue());
}

您如何知道这是否有效?在运行时它可能会抛出异常,它可能会工作,谁知道呢,这显然很糟糕。

您可能更想创建一个界面

public interface ValueProvider {
   Integer getValue();
}

并且只为 NodeA 实施。鉴于您的纸牌游戏示例,其中值可能是可选的,您 可以 考虑 returning null in getValue of NodeB .稍微好一点的方法可能是使用 Optional<Integer> 作为 getValue().

的 return 类型

然后你可以在 NodeA 中使用一个方法,例如:

@Override   
public Optional<Integer> getValue() {
    return Optional.of(this.value);
}

并在 NodeB

@Override   
public Optional<Integer> getValue() {
    return Optional.empty();
}

在基本层面上, 你的设计是错误的; 你正在打破封装。 我称之为 LRN2OOP

与其循环遍历卡片集合并将值相加, 您应该遍历卡片集合并将每张卡片的值添加到累加器。 具体来说, 卡片 class 的客户端不需要了解卡片值的内部表示(这是访客模式)。

这不是一个很好的解决方案, 但这是一个代码示例:

public interface CardScoreBlammy
{
  void addToScore(int cardScore);
}

public interface MyCard
{
   void accumulateScore(ScoreBlammy);

   ... other shared Card functionality.
}

public class CardHolder
implements CardScoreBlammy
{
  private int accumumatedScore = 0;
  private List<MyCard> cardList;
  ... populate the cardList somehow.

  public void addToScore(final int cardScore)
  {
    accumulatedScore += cardScore;
  }

  public int getScoreTotal()
  {
    accumulatedScore = 0;

    for (final MyCard currentCard : cardList)
    {
      currentCard.accumulateScore(this);
    }

    return accumulatedScore;
  }
}


public class NotAJoker
implements MyCard
{
  private int myValue;

  public void accumulateScore(final ScoreBlammy scoreBlammy)
  {
    scoreBlammy.addToScore(myValue)
  }
}

public class IRJoker
implements MyCard
{
  public void accumulateScore(final ScoreBlammy scoreBlammy)
  {
    // do nothing
  }
}

如果可能的话,我肯定会在这里重新评估您的设计策略。使用单个 class 并简单地 returning 0 for Joker 比您尝试做的要容易得多。

但是,如果出于某种原因这不是一个选项,那么接口将是一个不错的选择。创建一个 Card 接口并让两个 class 实现它。请注意在 return 类型中使用 Integer 而不是 int 以允许空值。此外,由于您已经知道非小丑牌的所有可能值,因此枚举可以很好地定义它:

public interface Card {
    public Integer getValue();
}

public class Joker implements Card {

    @Override
    public Integer getValue() {
        return null;
    }

}

public class NotJoker implements Card {
    private CARD_TYPE cardType;

    public NotJoker(CARD_TYPE type) {
        this.cardType = type;
    }

    public CARD_TYPE getType() {
        return cardType;
    }

    @Override
    public Integer getValue() {
        return cardType.getValue();
    }

}

public enum CARD_TYPE {
    ACE(11), KING(10), QUEEN(10), JACK(10),
    TEN(10), NINE(9), EIGHT(8), SEVEN(7),
    SIX(6), FIVE(5), FOUR(4), THREE(3),
    TWO(2);

    private final int value;

    CARD_TYPE(int value) {
        this.value = value;
    }

    public int getValue() {return value;}
}

现在我们可以创建 class 来存储卡片 Deck。我们只是对所有卡片使用 card.getValue(),并在添加其值之前检查结果 Integer 是否为 null

public class Deck {

    private ArrayList<Card> cardList;

    public Deck() {
        cardList = new ArrayList<Card>();
    }

    public void addCard(Card card) {
        cardList.add(card);
    }

    public int getTotalScore() {
        int totalScore = 0;

        for(Card card : cardList) {
            Integer value = card.getValue();
            if(value != null) {
                totalScore += value;
            }
        }
        return totalScore;
    }
}

这是一个证明它有效的快速测试:

public class CardGame {

    public static void main(String[] args) {

        Deck deck = new Deck();

        deck.addCard(new Joker());
        deck.addCard(new NotJoker(CARD_TYPE.FIVE));
        deck.addCard(new NotJoker(CARD_TYPE.FOUR));
        deck.addCard(new NotJoker(CARD_TYPE.ACE));
        deck.addCard(new NotJoker(CARD_TYPE.KING));
        deck.addCard(new Joker());
        deck.addCard(new NotJoker(CARD_TYPE.SEVEN));

        //total score: 37
        System.out.println("total score: " + deck.getTotalScore());
    }

}

这个问题的解决方案是不创建超类。你没问题:这是糟糕的设计。

我们对其进行了更改并创建了一个 class 卡片,其中包含两个 静态工厂方法 : 创建小丑() createNormalCard(int 值)

感谢您的所有回答。 你在几周内学到了很多东西。