其他人已经提出了我的最初想法,即矩阵方法,但是除了合并if语句外,您还可以通过确保提供的参数在预期范围内并使用就地返回(某些编码,可以避免使用某些方法)我见过的标准对函数强制执行一点退出,但是我发现多次返回对于避免箭头编码非常有用,并且由于Java中普遍存在异常,因此无论如何严格执行此类规则并没有多大意义因为方法中抛出的任何未捕获异常都可能是退出的起点)。嵌套switch语句是可能的,但是对于此处要检查的较小值范围,我发现语句是否更紧凑并且不太可能导致性能上的很大差异,
public int fightMath(int one, int two) {
if (one > 3 || one < 0 || two > 3 || two < 0) {
throw new IllegalArgumentException("Result is undefined for arguments outside the range [0, 3]");
}
if (one <= 1) {
if (two <= 1) return 0;
if (two - one == 2) return 1;
return 2; // two can only be 3 here, no need for an explicit conditional
}
// one >= 2
if (two >= 2) return 3;
if (two == 1) return 1;
return 2; // two can only be 0 here
}
最终,由于输入->结果映射的某些部分的不规则性,它最终的可读性比其他方式差。我更喜欢矩阵样式,因为它简单易用,以及如何将矩阵设置为在视觉上有意义(尽管这在一定程度上受我对卡诺地图的记忆的影响):
int[][] results = {{0, 0, 1, 2},
{0, 0, 2, 1},
{2, 1, 3, 3},
{2, 1, 3, 3}};
更新:考虑到您提到的阻止/击中,这是对函数的更根本的更改,该函数利用属性/属性保持枚举类型作为输入和结果,并且对结果进行了一些修改以说明阻止,这将导致更多可读功能。
enum MoveType {
ATTACK,
BLOCK;
}
enum MoveHeight {
HIGH,
LOW;
}
enum Move {
// Enum members can have properties/attributes/data members of their own
ATTACK_HIGH(MoveType.ATTACK, MoveHeight.HIGH),
ATTACK_LOW(MoveType.ATTACK, MoveHeight.LOW),
BLOCK_HIGH(MoveType.BLOCK, MoveHeight.HIGH),
BLOCK_LOW(MoveType.BLOCK, MoveHeight.LOW);
public final MoveType type;
public final MoveHeight height;
private Move(MoveType type, MoveHeight height) {
this.type = type;
this.height = height;
}
/** Makes the attack checks later on simpler. */
public boolean isAttack() {
return this.type == MoveType.ATTACK;
}
}
enum LandedHit {
NEITHER,
PLAYER_ONE,
PLAYER_TWO,
BOTH;
}
LandedHit fightMath(Move one, Move two) {
// One is an attack, the other is a block
if (one.type != two.type) {
// attack at some height gets blocked by block at same height
if (one.height == two.height) return LandedHit.NEITHER;
// Either player 1 attacked or player 2 attacked; whoever did
// lands a hit
if (one.isAttack()) return LandedHit.PLAYER_ONE;
return LandedHit.PLAYER_TWO;
}
// both attack
if (one.isAttack()) return LandedHit.BOTH;
// both block
return LandedHit.NEITHER;
}
如果要添加更多高度的块/攻击,您甚至不需要更改函数本身,只需添加枚举即可;但是,添加其他类型的动作可能需要修改功能。同样,EnumSet
s可能比使用额外的枚举作为主要枚举的属性具有更大的可扩展性,例如EnumSet<Move> attacks = EnumSet.of(Move.ATTACK_HIGH, Move.ATTACK_LOW, ...);
然后attacks.contains(move)
而不是move.type == MoveType.ATTACK
,尽管使用EnumSet
s可能比直接等于检查慢一些。
如果成功的区块导致产生计数器,您可以将替换if (one.height == two.height) return LandedHit.NEITHER;
为
if (one.height == two.height) {
// Successful block results in a counter against the attacker
if (one.isAttack()) return LandedHit.PLAYER_TWO;
return LandedHit.PLAYER_ONE;
}
另外,用if
三元运算符(boolean_expression ? result_if_true : result_if_false
)替换某些语句可以使代码更紧凑(例如,前面代码块中的代码将变为return one.isAttack() ? LandedHit.PLAYER_TWO : LandedHit.PLAYER_ONE;
),但这会导致难以理解的oneliner,所以我不会建议将其用于更复杂的分支。