我正在实施一个简单的“正确播放你的牌”(也称为高/低)游戏。如果您在规则非常简单之前没有遇到过它。使用一套卡片(例如心形)。一次绘制一张卡片,目的是正确猜测下一张卡片的面值是高于还是低于先前绘制的卡片的面值。
游戏的逻辑并不是特别复杂,我并不担心。我想出了一个设计,但我并不完全满意。有几个方面我确信它可以改进,这就是我想要你的建议。这是该类的接口(有关其他理解的注释,而不是真正的注释):
public interface PlayYourCardsRight {
/**
* Get the number of cards remaining with higher face values than the previously
* drawn card
* @return
*/
public abstract int getNumberCardsHigher();
/**
* Get the number of cards remaining with lower face values than the previously
* drawn card
* @return
*/
public abstract int getNumberCardsLower();
/**
* Get all cards that have already been drawn in the order they were drawn in
*
*/
public abstract List<Card> getPlayedCards();
/**
* Simple prediction algorithm - if there are more cards left in the deck with
* lower face values than the previous card, then predict 'Lower', if there
* are more cards left in the deck with higher face values then predict
* 'Higher', if there are equal numbers of higher/lower cards pick 'higher' or 'lower'
* at random
*
* Prediction is an Enum (Higher/Lower/None)
*
*/
public abstract Prediction getPrediction();
/*
* Draw the next card at random
*/
public abstract void nextRound();
/**
* Specifiy what the next card should be
*
* @param card
*/
public abstract void nextRound(Card card);
}
正如你所看到的,这一切都是相当自我解释和简单的。以下是我的问题:
我不希望构造函数自动绘制卡片。这意味着最初没有“先前抽取的卡片”。我在NO PREDICTION
枚举中有一个Prediction
值,但由于没有“先前绘制的卡片”,getNumberCardsHigher()
和getNumberCardsLower()
方法无法返回合理的值(它们不能当牌组中的所有牌都被抽出时,也会返回合理的值。
显然,我可以简单地抛出一个异常,但这似乎有点过分 - 特别是因为那时对方法的所有调用都必须包含在try / catches中。我也不满意返回一个负值,因为如果有人忘记/无法检查它们,那很容易导致一些错误。
欢迎所有建议!
答案 0 :(得分:3)
就个人而言,我认为在参数检查的情况下抛出未经检查的异常根本就不合适 - 这假设您的代码声明了一个无效状态(您不应该在该状态下使用该对象调用这些方法, EVER)。
我通常使用IllegalArgumentException来表明传入的参数不符合方法调用的约定,并且使用IllegalStateException来显示该对象此时未处于处理方法调用的状态。
由于它们都是未经检查的异常,因此您不必尝试/捕获它们,只是让它们冒泡,它们会执行异常擅长的事情 - 它们会为您提供堆栈跟踪并告诉您错误的确切位置包括谁不正确地打电话。
顺便说一下,我通常使用某种字符串,在你的情况下可能是:
throw new IllegalStateException("You cannot call this method until a card has been drawn");
从逻辑上讲,询问该卡是否高于或低于不存在的卡是没有意义的。
现在,如果您的方法实际上是异常,那么您必须继续修复您的代码,以便在它绘制卡片之前不会调用该方法 - 所以您必须弄清楚如何绘制您的第一张牌无论如何。
注意:例外仅用于错误检测,避免将它们用于流控制。这意味着您不应该尝试捕获异常并使用它来绘制卡然后再次调用!相反,您应该以这样的方式编程,以确保在第一次调用方法之前绘制卡片。
答案 1 :(得分:0)
我认为当没有先前的牌被绘制时,两种方法都应该返回card.count
。存在相同数量的较低和较高的卡,并且对于两者而言,卡计数更高/更低的卡比没有更多。然后,您的算法将起作用并返回NO_PREDICTION
。
答案 2 :(得分:0)
我个人建议在玩家做任何事之前先拿一张初始卡,因为让玩家在第一张牌启动之前做任何事都没有意义,但我认为“我不希望构造者自动画一张牌“意味着你不想那样做。如果你不想这样做,我会让函数抛出异常,并让代码调用它们(预测函数)特殊情况,游戏开始时返回“无预测”而不是试图调用它们。游戏结束不是特例;这两个函数都应该返回0
,因为没有卡高于或低于套牌中剩余的向上卡
此外,无需在界面中声明每个函数abstract
,它是自动且必需的
答案 3 :(得分:0)
我不希望构造函数自动绘制卡片。这意味着最初没有“先前抽取的卡片”。我在预测枚举中有一个NO PREDICTION值但是,由于没有“先前绘制的卡片”,getNumberCardsHigher()和getNumberCardsLower()方法无法返回合理的值(当来自卡片组的所有卡片时,它们也无法返回合理的值已经画了。)
我认为API混淆的原因是你的PlayYourCardsRight
界面试图模拟两个不同的东西:游戏引擎/规则和卡片组。我会将卡片组的状态和剩余的卡片计数方法移动到Deck
类。我会将API更改为getNumberCards[Higher/Lower](Card)
并让游戏引擎指定您想要比较哪张牌,而不是期望牌组记住最后绘制的牌,我将其视为游戏状态的一个元素,而不是甲板上的。
我强烈建议编写一些JUnit测试。 TDD有助于产生一个内聚的,解耦的API。