วิธีที่ดีที่สุดในการจัดรูปแบบคำสั่ง if ที่มีหลายเงื่อนไข


90

หากคุณต้องการให้โค้ดบางตัวดำเนินการตามเงื่อนไขตั้งแต่สองเงื่อนไขขึ้นไปซึ่งเป็นวิธีที่ดีที่สุดในการจัดรูปแบบคำสั่ง if

ตัวอย่างแรก: -

if(ConditionOne && ConditionTwo && ConditionThree)
{
   Code to execute
}

ตัวอย่างที่สอง: -

if(ConditionOne)
{
   if(ConditionTwo )
   {
     if(ConditionThree)
     {
       Code to execute
     }
   }
}

ซึ่งง่ายที่สุดในการทำความเข้าใจและอ่านโดยคำนึงว่าแต่ละเงื่อนไขอาจเป็นชื่อฟังก์ชันที่ยาวหรืออะไรก็ได้


น่าเสียดายที่ไม่มีใครในหน้านี้พูดถึงสตริงย่อย "เร็ว" หรือ "ประสิทธิภาพ" นั่นคือสิ่งที่ฉันมาที่นี่เพื่อเรียนรู้
Dreamspace President

คำตอบ:


133

ฉันชอบตัวเลือก A

bool a, b, c;

if( a && b && c )
{
   //This is neat & readable
}

หากคุณมีตัวแปร / เงื่อนไขวิธีการที่ยาวเป็นพิเศษคุณสามารถขีดเส้นแบ่งได้

if( VeryLongConditionMethod(a) &&
    VeryLongConditionMethod(b) &&
    VeryLongConditionMethod(c))
{
   //This is still readable
}

ถ้ามันซับซ้อนกว่านี้ฉันจะพิจารณาใช้วิธีเงื่อนไขแยกต่างหากนอกคำสั่ง if

bool aa = FirstVeryLongConditionMethod(a) && SecondVeryLongConditionMethod(a);
bool bb = FirstVeryLongConditionMethod(b) && SecondVeryLongConditionMethod(b);
bool cc = FirstVeryLongConditionMethod(c) && SecondVeryLongConditionMethod(c);

if( aa && bb && cc)
{
   //This is again neat & readable
   //although you probably need to sanity check your method names ;)
}

IMHO เหตุผลเดียวสำหรับตัวเลือก "B" คือถ้าคุณมีelseฟังก์ชันแยกกันเพื่อเรียกใช้สำหรับแต่ละเงื่อนไข

เช่น

if( a )
{
    if( b )
    {
    }
    else
    {
        //Do Something Else B
    }
}
else
{
   //Do Something Else A
}

ฉันชอบมัน. แม้ว่าฉันจะไม่ใช่แฟนตัวยงของแนวคิดวิธีการเว้นแต่ว่ามีวิธีการอยู่แล้วและส่งคืนค่าบูลีน
Thomas Owens

2
คุณประเมินทุกอย่างโดยไม่มีเหตุผลในตัวอย่างที่สองไม่ใช่หรือ
Odys

ฉันจะใช้ '&&' ก่อนเงื่อนไข ยากที่จะมีเงื่อนไขที่มีความยาวอักขระเดียวกันกับในตัวอย่าง
AdrianN

29

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

if(MyChecksAreOk()) { Code to execute }

...

private bool MyChecksAreOk()
{ 
    return ConditionOne && ConditionTwo && ConditionThree;
}

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


2
ฉันพบว่าสิ่งนี้มีประสิทธิภาพมากที่สุดและง่ายต่อการเพิ่มเงื่อนไขในภายหลัง
pbojinov

+1 ตอนแรกฉันเลิกคิ้ว แต่นี่เป็นคำตอบที่ดีที่สุดจริงๆ การมีบูลีนisOkToDoWhateverเป็นคุณสมบัตินั้นสมเหตุสมผลมาก
ยิ้ม

1
แต่นี่ก็ย้ายเงื่อนไขที่ซับซ้อนแบบเดียวกันไปที่อื่นซึ่งจำเป็นต้องอ่านได้ด้วยดังนั้นเราจึงกลับไปที่กำลังสองด้วยสิ่งนี้ ไม่ใช่แค่ifความสามารถในการอ่านคำสั่งเท่านั้น แต่เป็นการอ่านเงื่อนไข
Robert Koritnik

@RobertKoritnik ฉันเข้าใจสิ่งที่คุณกำลังพูด แต่ฉันไม่คิดว่าเราจะกลับไปที่กำลังสองเพราะเราได้ลดความซับซ้อนที่ผู้อ่านต้องพิจารณาในครั้งเดียว เธออาจดูเงื่อนไขหรือเธออาจดูรหัสโดยใช้เงื่อนไขที่เงื่อนไขมีชื่อที่ดี (หวังว่า) อย่างน้อยฉันก็มักจะพบว่ามันง่ายกว่านี้ แต่บางครั้งก็เป็นเรื่องดีที่มีรายละเอียดทั้งหมดในที่เดียว เช่นเคยขึ้นอยู่กับ
Torbjørn

จุดยอดเยี่ยมในการใช้ชื่อวิธีการที่ดีและการปรับโครงสร้างใหม่ของตรรกะ
JB Lovell

10

ตัวอย่างแรกคือ "อ่านง่าย" มากกว่า

ที่จริงแล้วในความคิดของฉันคุณควรใช้อันที่สองเมื่อใดก็ตามที่คุณต้องเพิ่ม "else logic" แต่สำหรับ Conditional ธรรมดาให้ใช้รสแรก หากคุณกังวลเกี่ยวกับเงื่อนไขที่ยาวนานคุณสามารถใช้ไวยากรณ์ถัดไปได้เสมอ:

if(ConditionOneThatIsTooLongAndProbablyWillUseAlmostOneLine
                 && ConditionTwoThatIsLongAsWell
                 && ConditionThreeThatAlsoIsLong) { 
     //Code to execute 
}

โชคดี!


10
if (   ( single conditional expression A )
    && ( single conditional expression B )
    && ( single conditional expression C )
   )
{
   opAllABC();
}
else
{
   opNoneABC();
}

การจัดรูปแบบนิพจน์เงื่อนไขหลายรายการในคำสั่ง if-else ด้วยวิธีนี้:

  1. ช่วยให้การอ่านเพิ่มขึ้น:
    การดำเนินการตรรกะไบนารีทั้งหมด {&&, ||} ในนิพจน์ที่แสดงก่อน
    b. ทั้งสองตัวถูกดำเนินการตามเงื่อนไขของแต่ละการดำเนินการไบนารีนั้นชัดเจนเนื่องจากจัดแนวในแนวตั้ง
    c การดำเนินการนิพจน์ตรรกะที่ซ้อนกันจะทำให้ชัดเจนโดยใช้การเยื้องเช่นเดียวกับการซ้อนคำสั่งภายในประโยค
  2. ต้องมีวงเล็บที่ชัดเจน (ไม่ต้องอาศัยกฎลำดับความสำคัญของตัวดำเนินการ)
    ก. สิ่งนี้หลีกเลี่ยงข้อผิดพลาดในการวิเคราะห์แบบคงที่ทั่วไป
  3. ช่วยให้การดีบัก
    ไฟล์. ปิดการใช้งานการทดสอบตามเงื่อนไขเดี่ยวแต่ละรายการโดยใช้ a //
    b กำหนดจุดพักก่อนหรือหลังการทดสอบแต่ละครั้ง
    ...
// disable any single conditional test with just a pre-pended '//'
// set a break point before any individual test
// syntax '(1 &&' and '(0 ||' usually never creates any real code
if (   1
    && ( single conditional expression A )
    && ( single conditional expression B )
    && (   0
        || ( single conditional expression C )
        || ( single conditional expression D )
       )
   )
{
   ... ;
}

else
{
   ... ;
}

นี่คือวิธีการของฉัน ปัญหาเดียวที่ฉันมีคือฉันยังไม่พบเครื่องตกแต่งรหัสซึ่งเสนอสิ่งนี้เป็นตัวเลือก
Speed8ump

9

คำถามถูกถามและจนถึงขณะนี้ได้รับคำตอบราวกับว่าการตัดสินใจควรใช้เหตุผล "วากยสัมพันธ์" ล้วนๆ

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

หากการทดสอบสองครั้งเป็นสองด้านของเหรียญเดียวกันเช่น ถ้า (x> 0) && (x <= 100) จากนั้นนำมารวมกันในบรรทัดเดียวกัน ถ้าเงื่อนไขอื่นอยู่ไกลจากแนวคิดเช่น user.hasPermission (Admin ()) แล้ววางไว้ในบรรทัดของตัวเอง

เช่น.

if user.hasPermission(Admin()) {
   if (x >= 0) && (x < 100) {
      // do something
   }
}


3

อันแรกง่ายกว่าเพราะถ้าคุณอ่านจากซ้ายไปขวาคุณจะได้รับ: "If something AND somethingelse AND somethingelse THEN" ซึ่งเป็นประโยคที่เข้าใจง่าย ตัวอย่างที่สองอ่านว่า "If something THEN if somethingelse then if something else then" ซึ่งดูเงอะงะ

นอกจากนี้ให้พิจารณาว่าคุณต้องการใช้ OR บางส่วนในประโยคของคุณหรือไม่คุณจะทำอย่างไรในลักษณะที่สอง


0

ใน Perl คุณสามารถทำได้:

{
  ( VeryLongCondition_1 ) or last;
  ( VeryLongCondition_2 ) or last;
  ( VeryLongCondition_3 ) or last;
  ( VeryLongCondition_4 ) or last;
  ( VeryLongCondition_5 ) or last;
  ( VeryLongCondition_6 ) or last;

  # Guarded code goes here
}

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


1
ที่ดูน่ากลัว - ใน "มันทำอะไร" ความรู้สึก;) แต่มันสามารถอ่านได้จริงเมื่อคุณคุ้นเคยกับมัน
Piskvor ออกจากอาคาร

-2

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

หากไม่มีทางเลือกอื่นเหมือนที่คนอื่นแนะนำให้แยกย่อยออกเป็นแยกจากกันแล้วย่อชื่อหรือจัดกลุ่มและเช่นถ้าทั้งหมดต้องเป็นจริงให้ใช้คำสั่งเช่น "if no false in array of x then run"

หากทุกอย่างล้มเหลว @Eoin Campbell ให้ความคิดที่ดีงาม


นี่ไม่ใช่การเพิ่มอะไรใหม่ให้กับคำตอบที่มีอยู่แล้ว
jerney

-4

เมื่อเงื่อนไขซับซ้อนมากฉันใช้สไตล์ต่อไปนี้ (ตัวอย่างชีวิตจริงของ PHP):

if( $format_bool &&
    (
        ( isset( $column_info['native_type'] )
            && stripos( $column_info['native_type'], 'bool' ) !== false
        )
        || ( isset( $column_info['driver:decl_type'] )
            && stripos( $column_info['driver:decl_type'], 'bool' ) !== false
        )
        || ( isset( $column_info['pdo_type'] )
            && $column_info['pdo_type'] == PDO::PARAM_BOOL
        )
    )
)

ฉันเชื่อว่ามันดีและอ่านง่ายกว่าการซ้อนif()ไฟล์. และในบางกรณีเช่นนี้คุณจะไม่สามารถแบ่งเงื่อนไขที่ซับซ้อนออกเป็นชิ้น ๆ ได้เพราะไม่เช่นนั้นคุณจะต้องทำคำสั่งเดิมซ้ำif() {...}หลาย ๆ ครั้ง

ฉันยังเชื่อว่าการเพิ่ม "อากาศ" ลงในโค้ดเป็นความคิดที่ดีเสมอ ช่วยเพิ่มการอ่านอย่างมาก

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