Orang lain telah menyarankan ide awal saya, metode matriks, tetapi selain mengkonsolidasikan pernyataan if, Anda dapat menghindari sebagian dari apa yang Anda miliki dengan memastikan argumen yang disediakan berada dalam kisaran yang diharapkan dan dengan menggunakan pengembalian di tempat (beberapa pengkodean standar yang saya lihat menerapkan satu titik keluar untuk fungsi, tetapi saya telah menemukan bahwa banyak pengembalian sangat berguna untuk menghindari pengkodean panah dan dengan prevalensi pengecualian di Jawa tidak ada banyak gunanya secara ketat menegakkan aturan seperti itu pula karena setiap pengecualian yang tidak tertangkap yang dilemparkan ke dalam metode ini mungkin adalah titik keluar). Pernyataan peralihan yang bersarang adalah suatu kemungkinan, tetapi untuk rentang nilai yang kecil yang Anda periksa di sini, saya menemukan jika pernyataan menjadi lebih ringkas dan tidak cenderung menghasilkan banyak perbedaan kinerja,
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
}
Ini akhirnya menjadi kurang dapat dibaca daripada mungkin karena ketidakteraturan bagian-bagian dari pemetaan input-> hasil. Saya lebih menyukai gaya matriks karena kesederhanaannya dan bagaimana Anda dapat mengatur matriks agar masuk akal secara visual (meskipun itu sebagian dipengaruhi oleh ingatan saya akan peta Karnaugh):
int[][] results = {{0, 0, 1, 2},
{0, 0, 2, 1},
{2, 1, 3, 3},
{2, 1, 3, 3}};
Pembaruan: Mengingat Anda menyebutkan pemblokiran / pemukulan, berikut ini adalah perubahan yang lebih radikal pada fungsi yang menggunakan tipe enumerated properti-holding yang disebutkan untuk input dan hasilnya dan juga memodifikasi hasil sedikit untuk memperhitungkan pemblokiran, yang akan menghasilkan lebih banyak fungsi yang dapat dibaca.
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;
}
Anda bahkan tidak perlu mengubah fungsi itu sendiri jika Anda ingin menambahkan blok / serangan yang lebih tinggi, hanya enum; menambahkan jenis gerakan tambahan mungkin akan membutuhkan modifikasi fungsi. Juga, EnumSet
s mungkin lebih dapat diperluas daripada menggunakan enum tambahan sebagai properti enum utama, misalnya EnumSet<Move> attacks = EnumSet.of(Move.ATTACK_HIGH, Move.ATTACK_LOW, ...);
dan kemudian attacks.contains(move)
daripada move.type == MoveType.ATTACK
, meskipun menggunakan EnumSet
s mungkin akan sedikit lebih lambat daripada langsung sama dengan cek.
Untuk kasus di mana blok yang berhasil menghasilkan penghitung, Anda dapat menggantinya if (one.height == two.height) return LandedHit.NEITHER;
dengan
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;
}
Juga, mengganti beberapa if
pernyataan dengan penggunaan operator ternary ( boolean_expression ? result_if_true : result_if_false
) dapat membuat kode lebih kompak (misalnya, kode di blok sebelumnya akan menjadi return one.isAttack() ? LandedHit.PLAYER_TWO : LandedHit.PLAYER_ONE;
), tetapi itu dapat menyebabkan oneliners yang lebih sulit dibaca sehingga saya tidak akan ' t merekomendasikannya untuk percabangan yang lebih kompleks.