ควรจัดทำงบ / อื่นโดยความหายากของกรณีหรือความยากลำบากในการจัดการกับพวกเขา?


18

ในรหัสที่ฉันกำลังเขียนตอนนี้ฉันมีสิ่งนี้:

if (uncommon_condition) {
    do_something_simple();
} else {
    do();
    something();
    long();
    and();
    complicated();
}

ส่วนหนึ่งของฉันคิดว่า "ไม่เป็นไรวิธีเขียนกรณีง่าย ๆ ควรไปก่อนและกรณีที่ซับซ้อนกว่าควรไปต่อไป" แต่อีกส่วนหนึ่งกล่าวว่า: "ไม่! elseรหัสควรอยู่ภายใต้ifเนื่องจากifสำหรับการจัดการกับกรณีที่ผิดปกติและelseสำหรับการจัดการกับกรณีอื่น ๆ ทั้งหมด" ข้อใดถูกหรือดีกว่า?


4
สั่งโดยความเรียบง่าย / เข้าใจเงื่อนไข! ส่วนที่เหลือสามารถได้รับการดูแลโดยเครื่องมือเพิ่มประสิทธิภาพการพยากรณ์สาขาและการปรับโครงสร้างใหม่
Marjan Venema

นี่คือเหตุผลที่เราได้รับเงินจำนวนมากเพื่อทำการตัดสินใจที่ยากลำบากเหล่านี้

คำตอบ:


24

เรียงลำดับตามโอกาสในการถูกประหารชีวิต เงื่อนไขที่พบได้บ่อยที่สุดและเป็นไปได้ ฯลฯ ควรเป็นอันดับแรก

"ความยากลำบากในการจัดการกับพวกเขา" ควรได้รับการจัดการโดยโครงสร้างของรหัส, นามธรรม, เป็นต้นในตัวอย่างบล็อกอื่นสามารถ refactored เพื่อเรียกวิธีการเดียว คุณต้องการให้ifคำสั่งของคุณอยู่ในระดับนามธรรมเดียวกัน

if ( ! LotteryWinner ) {
    GoToWorkMonday();
} else {
    PlanYearLongVacation();
}

6
เพื่อประสิทธิภาพฉันอาจเห็นด้วย แต่จากนั้นอีกครั้งตัวปรับประสิทธิภาพสูงสุดและตัวทำนายสาขามีความสามารถในการดูแลอย่างสมบูรณ์แบบ เพื่อความสะดวกในการอ่านฉันอาจเห็นด้วยว่ากรณีที่เป็นไปได้มากที่สุดจะมีบรรทัดมากกว่าที่เป็นไปได้น้อยกว่า notแต่กับผมว่าจะเร็วบ่งบอกถึงความจำเป็นที่จะต้องดึงวิธีมากกว่าที่จะใช้งาน โดยส่วนตัวแล้วฉันจะมีสมาธิกับการหลีกเลี่ยงnotเงื่อนไข พวกเขาได้รับการพิสูจน์แล้วว่าทำให้เกิดภาระการรับรู้มากขึ้นเพื่อทำความเข้าใจมากกว่าเงื่อนไข "บวก" และเป็นอันตรายต่อความสามารถในการอ่าน / ทำความเข้าใจของรหัส ฉันมักจะใช้พวกเขาในงบยามเท่านั้น
Marjan Venema

2
@MarjanVenema ฉันเห็นจุดของคุณเกี่ยวกับ "ไม่" ing แต่ค่าลบสองเท่าคือ WTF ที่แท้จริง "ไม่ใช่" วันที่ฉันวิ่งอื่น ๆ doesNotAllowxxFiles = falseลงในรหัสของเรา ไม่ดีพอ แต่ทำเช่นนี้if(! doesNotAllowxxFiles)
Radarbob

ใช่ฟิล์มเนกาทีฟเชิงลบรวมกับและของและ / หรือ (sic!) และเนกาทีฟรวมกับวิธีการ / var ด้วยไม่อยู่ในชื่อได้รับสมองของฉันในการบิดทุกครั้ง :-)
Marjan Venema

หากคุณพบว่าตัวเองมีปัญหาในการทำความเข้าใจว่าเกิดอะไรขึ้นฉันคิดว่ามันมักจะมีประโยชน์ที่จะทำสิ่งที่ชอบ: simpleBool = (! (complexBool || randomfFlag)) &&! randomFlag
TruthOf42

2
ฉันจะเห็นด้วยกับคุณยกเว้นการดำรงอยู่ของ Guard Clauses (ซึ่งมักจะมีเงื่อนไขพิเศษในส่วนนั้นของคำสั่ง IF ไม่ใช่เงื่อนไขทั่วไป)
Robert Harvey

5

พยายามปรับปรุงความสามารถในการอ่าน วิธีหนึ่งคือการวางบล็อกโค้ดที่ยาวขึ้นในส่วนอื่น

if (s == null)
     // short code
else 
     // long 
     // code
     // block

สามารถอ่านได้มากกว่า

if (s != null)
    // long
    // code
    // block
else
    // short code

2
เหตุใดจึงอ่านได้มากกว่า ฉันไม่เห็นความแตกต่างระหว่างทั้งสองในแง่ของการอ่าน
John Demetriou

2
@JohnDemetriou The Else นั้นมองเห็นได้ชัดเจนยิ่งขึ้นถ้า the นั้นสั้น ผู้คนสแกนหาโครงสร้างก่อนจากนั้นจึงกำหนดความหมาย โค้ดที่ไม่มี Else นั้นแตกต่างจากโค้ดที่มีหนึ่งดังนั้นการทำให้ Else นั้นมองเห็นได้ชัดเจนขึ้นนั้นเป็นที่เข้าใจได้มากขึ้น (ทุกสิ่งเท่าเทียมกันในวันอังคารที่ไม่ฝนตก ฯลฯ )

4

ไม่มีกฎตายตัวเช่นฉันได้ยินเกี่ยวกับการใช้งาน แต่ฉันทำตามเช่นนี้

if(usual)
{
(more often)
}
else (unusual)
{
(rarely occurring)
}

แต่ถ้าทั้งคู่มีฟังก์ชั่นเดียวกันกับคุณสมบัติที่แตกต่างกันไปก่อนดีกว่าปกติแล้วเพื่อให้คุณสามารถบันทึกคำสั่งหนึ่ง


if(x == 0)  // 1
  {x = 1;}  // 2
else
  {x = 2;}  // 3

สำหรับรหัสประกอบรหัสด้านบนจะเป็นดังนี้:

1. 000d 837DFC00        cmpl    $0, -4(%ebp)
   0011 7509            jne .L2

2. 0013 C745FC01        movl    $1, -4(%ebp)
   001a EB07            jmp .L3

    .L2:
3.001c C745FC02         movl    $2, -4(%ebp)

        .L3:

ถ้าเงื่อนไขภายในถ้าเป็นจริงแล้วการไหลคือ 1-> 2 (4 intructions)
หากเงื่อนไขภายในถ้าเป็นเท็จแล้วการไหลเป็น 1-> 3 (3 intructions)

ดังนั้นจึงเป็นการดีที่จะใส่เหตุการณ์ที่ผิดปกติหรือไม่ค่อยเกิดขึ้นในส่วนอื่นและสภาพปกติเพื่อให้เราสามารถบันทึกคำสั่งได้ทุกครั้ง ;-)


2

ฉันพบว่ารูปแบบตรงข้ามที่แน่นอนนำไปสู่การอ่านรหัสได้ง่ายขึ้นและลดหรือกำจัดคำสั่งที่ซ้อนกัน ฉันหมายถึงสิ่งนี้เป็นรูปแบบ "ถุงมือ" (ในการเล่าเรื่องถุงมือจะเป็นชุดของความท้าทายที่จะต้องประสบความสำเร็จก่อนที่งานสุดท้ายจะเสร็จสมบูรณ์) โดยการจัดการกรณีขอบของคุณก่อนคุณอนุญาตให้ตัวหลักของรหัสของคุณสะอาดและรัดกุม:

if(gauntlet_1){ handle the first gauntlet condition }; 
if(gauntlet_2){ handle the second gauntlet condition };
...
// All preconditions (gauntlets) have been successfully handled

// Perform your main task here

ดังนั้นส่วน "ด้ามถุงมือ" จะต้องมีการโอนการควบคุมเช่นการโยนหรือกลับคำสั่งหรือจะต้องแก้ไขข้อผิดพลาดจริง บางคนขมวดคิ้วกับชุดของถ้า ... ส่งคืนงบ แต่ฉันไม่คิดว่าในความเป็นจริงแล้วทำให้รหัสอ่านง่ายขึ้นตามที่คุณพูด

1
หากเงื่อนไขถุงมือเป็นสิ่งที่จะป้องกันไม่ให้ฟังก์ชั่นสำเร็จก็จะส่งกลับข้อผิดพลาดทันที หากเงื่อนไขของถุงมือสามารถจัดการได้ฉันต้องทำก่อนที่จะเข้าสู่เนื้อหาหลักของรหัสทุกครั้งที่ทำได้ ฉันพยายามหลีกเลี่ยงคำสั่ง IF ที่ซ้อนกันซึ่งจากประสบการณ์ของฉันเป็นหนึ่งในสาเหตุหลักของการปิดบังและยากที่จะดีบักข้อผิดพลาดในการเขียนโปรแกรม
Byron Jones

0

สำหรับฉันมันเกี่ยวกับเงื่อนไขมากกว่าความซับซ้อนของรหัสที่พวกเขาเรียกใช้ คุณจำเป็นต้องสั่งเงื่อนไขเพื่อดักจับเงื่อนไขที่ผิดปกติก่อน นอกจากนี้หากรหัสอื่นยาวและซับซ้อนจริง ๆ ฉันอาจทำย่อยเพื่อให้ส่วนที่มีเงื่อนไขชัดเจนสำหรับผู้อ่าน


-1

ฉันไม่มีกฎตายตัว แต่โดยทั่วไปฉันทำตามสิ่งนี้ - ก่อนอื่นให้พิจารณาว่ามีรูปแบบการออกแบบที่ไม่ได้รับซึ่งจะคำนึงถึงเรื่องนี้อย่างไร ถ้าไม่ฉันเขียนมันเพื่อให้เงื่อนไขในถ้าเป็นที่ชัดเจนที่สุด นั่นคือหลีกเลี่ยงเชิงลบสองเท่าและไม่ชอบ


-1

สำหรับสถานการณ์ดังกล่าวไม่มีกฎง่ายๆสำหรับมัน แต่อาจเป็นไปได้ว่าเราสามารถติดตามเพื่อเขียนโค้ดเชิงบวกหรือเป็นไปได้มากที่สุดใน if block และปล่อยไว้ในบล็อกอื่นหรือกรณีเริ่มต้น


สิ่งนี้ไม่ได้ให้สิ่งใดเกินกว่าสิ่งที่อธิบายไว้แล้วในคำตอบก่อนหน้านี้ - programmers.stackexchange.com/a/223093/31260และprogrammers.stackexchange.com/a/223520/31260
gnat
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.