คนอื่นได้แนะนำแนวคิดเริ่มต้นของฉันแล้ววิธีเมทริกซ์ แต่นอกเหนือจากการรวมคำสั่ง if คุณสามารถหลีกเลี่ยงบางสิ่งที่คุณมีโดยทำให้แน่ใจว่าข้อโต้แย้งที่ให้นั้นอยู่ในช่วงที่คาดหวังและโดยใช้การส่งคืนแบบแทน มาตรฐานที่ฉันเคยเห็นบังคับให้ใช้จุดเดียวออกจากฟังก์ชั่น แต่ฉันพบว่าผลตอบแทนหลายรายการมีประโยชน์มากสำหรับการหลีกเลี่ยงการเข้ารหัสลูกศรและด้วยความชุกของข้อยกเว้นใน Java ไม่มีจุดใดที่บังคับใช้กฎดังกล่าวอย่างเคร่งครัดอยู่แล้ว เนื่องจากมีข้อยกเว้นที่ไม่ถูกตรวจจับใด ๆ ที่ถูกโยนเข้าไปในวิธีการนั้นเป็นจุดออกที่เป็นไปได้) คำสั่งสวิตช์ซ้อนเป็นไปได้ แต่สำหรับช่วงเล็ก ๆ ของค่าที่คุณกำลังตรวจสอบที่นี่ฉันพบว่าคำสั่งมีขนาดกะทัดรัดและไม่น่าจะส่งผลให้เกิดความแตกต่างด้านประสิทธิภาพมากนัก
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
}
นี่จะจบลงด้วยการอ่านน้อยกว่ามันอาจเป็นเพราะความผิดปกติของส่วนต่าง ๆ ของการแมปอินพุท -> ฉันชอบสไตล์เมทริกซ์แทนเนื่องจากความเรียบง่ายและวิธีที่คุณสามารถตั้งค่าเมทริกซ์เพื่อให้เห็นภาพได้ (แม้ว่าส่วนนั้นจะได้รับอิทธิพลจากความทรงจำของแผนที่ Karnaugh ของฉัน):
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อาจขยายได้มากกว่าการใช้ enums พิเศษเป็นคุณสมบัติของ enum หลักเช่น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;
) แต่นั่นอาจทำให้ผู้อ่านยากขึ้น ไม่แนะนำสำหรับการแยกที่ซับซ้อนมากขึ้น