Diğer insanlar ilk fikrimi, matris yöntemini zaten önerdiler, ancak if ifadelerini birleştirmeye ek olarak, sağlanan argümanların beklenen aralıkta olduğundan ve yerinde dönüşler (bazı kodlama) kullanarak sahip olduğunuz şeylerden bazılarını önleyebilirsiniz. Standartlar işlevler için bir çıkış noktası uyguladığını gördüm, ancak ok kodlamasından kaçınmak için birden fazla dönüşün çok yararlı olduğunu gördüm ve Java'daki istisnaların yaygınlığıyla, böyle bir kuralın kesinlikle uygulanmasının pek bir anlamı yok çünkü yönteme atılan yakalanmamış istisnalar olası bir çıkış noktasıdır). Anahtar ifadelerini iç içe yerleştirme bir olasılıktır, ancak burada kontrol ettiğiniz küçük değer aralığı için ifadelerin daha kompakt olup olmadığını ve performans farkının çoğuyla sonuçlanmasının olası olmadığını,
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
}
Bu, aksi takdirde giriş-> sonuç eşlemesinin parçalarının düzensizliğinden kaynaklanabileceğinden daha az okunabilir hale gelir. Basitliği ve matrisi görsel olarak mantıklı hale getirmek için nasıl ayarlayabileceğinizi yerine matris stilini tercih ediyorum (bu kısmen Karnaugh haritalarındaki anılarımdan etkileniyor):
int[][] results = {{0, 0, 1, 2},
{0, 0, 2, 1},
{2, 1, 3, 3},
{2, 1, 3, 3}};
Güncelleme: Engelleme / isabetten bahsettiğinizde, girişler ve sonuç için doğrulanmış / öznitelik tutma numaralandırılmış türlerini kullanan ve ayrıca engelleme için sonucu biraz değiştirecek şekilde işlevde daha radikal bir değişiklik. okunabilir işlev.
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;
}
Daha yükseklikte bloklar / saldırılar eklemek istiyorsanız, yalnızca numaralandırmalar işlevinin kendisini değiştirmek zorunda bile değilsiniz; Ancak, ek hareket türleri eklemek muhtemelen işlevin değiştirilmesini gerektirecektir. Ayrıca, EnumSet
s enumları ana enumun özellikleri olarak kullanmaktan daha uzatılabilir, örneğin EnumSet<Move> attacks = EnumSet.of(Move.ATTACK_HIGH, Move.ATTACK_LOW, ...);
ve daha attacks.contains(move)
ziyade move.type == MoveType.ATTACK
, EnumSet
s'yi kullanmak muhtemelen doğrudan eşit denetimlerden biraz daha yavaş olacaktır.
Başarılı bir bloğun bir sayaçla sonuçlanması durumunda 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;
}
Ayrıca, bazı if
ifadelerin üçlü operatör ( boolean_expression ? result_if_true : result_if_false
) kullanımı ile değiştirilmesi , kodu daha kompakt hale getirebilir (örneğin, önceki bloktaki kod haline gelir return one.isAttack() ? LandedHit.PLAYER_TWO : LandedHit.PLAYER_ONE;
), ancak bu, daha zor okunan onelinerlere yol açabilir. t Daha karmaşık dallanmalar için tavsiye etmem.