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

时间:2019-01-04 15:21:25

标签: java software-design subtitle

想象一下…… 我有两节课: NodeA和NodeB。 NodeA存储一个Integer并具有一个getter方法。 NodeB没有。

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

在下面的代码中, NodeB引发异常。 超类节点具有最优的。

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。普通卡有一个值,笑话没有。我想要一个超类的原因是我可以创建一个列表

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

由于笑话没有值,因此我必须检查卡片是否为笑话。如果没有,则将其强制转换为NormalCard并获取该值。我的老师说,演员阵容是邪恶的。...所以我在寻找替代品。

4 个答案:

答案 0 :(得分:2)

最简单的答案是:您不会。

稍长的答案:如果您认为需要这样做,则应该改进设计。这违反了OO设计原则,尤其是LSP

仅使用以下方法进行成像:

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

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

您可能想要创建一个界面

public interface ValueProvider {
   Integer getValue();
}

,并且仅为NodeA实现。在您的纸牌游戏示例中,值可能是可选的,您可以可以考虑在null的{​​{1}}中返回getValue。更好的方法可能是使用NodeB作为Optional<Integer>的返回类型。

然后,您可以在getValue()中使用如下方法:

NodeA

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

NodeB

答案 1 :(得分:1)

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

与其循环浏览一系列卡片并累加价值, 您应该遍历纸牌集合,并让每张纸牌将其价值添加到累加器中。 特别, 不需要Card类的客户知道Card值的内部表示形式(这是Visitor模式)。

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

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
  }
}

答案 2 :(得分:0)

如果可以的话,我绝对会在这里重新评估您的设计策略。仅使用一个类并简单地为Joker返回0比您尝试做的要容易得多。

但是,如果由于某种原因这不是一个选择,那么接口将是一个不错的选择。创建一个Card接口,并让两个类都实现它。请注意,在返回类型中使用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;}
}

现在,我们可以创建用于存储卡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());
    }

}

答案 3 :(得分:0)

此问题的解决方案是不要创建超级句。您还好:这是糟糕的设计。

我们进行了更改,并使用两种静态工厂方法创建了一个类卡: createJoker() createNormalCard(int value)

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