想象一下…… 我有两节课: 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并获取该值。我的老师说,演员阵容是邪恶的。...所以我在寻找替代品。
答案 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)
感谢您的所有回答。 您将在几周内学到很多东西。