ใช้อย่างอื่นหลังจากข้อยกเว้น (หรือไม่)


9

พิจารณารหัสนี้หน่อย:

if (x == 1)
{
  throw "no good; aborting" ;
}

[... more code ...]

พิจารณารหัสนี้:

if (x == 1)
{
  throw "no good; aborting" ;
}
else
{
  [... more code ...]
}

ทั้งสองกรณีทำงานในลักษณะเดียวกัน กรณีแรกที่มีประโยชน์ที่คุณจะได้ไม่ต้อง "ห่อ" elseส่วนที่เหลือของรหัสในนั้น ประการที่สองมีความได้เปรียบดังต่อไปนี้การปฏิบัติของอย่างชัดเจนมีที่สำหรับทุกคนelseif

ทุกคนสามารถให้ข้อโต้แย้งที่มั่นคงในความโปรดปรานของหนึ่งมากกว่าอีก?


5
การปฏิบัติที่คุณอ้างถึงชัดเจนชัดเจนelseว่าเป็นการหลอกลวง บ่อยครั้งที่ไม่มีอะไรจะใส่ลงในelseบล็อกได้เว้นแต่คุณจะก้มตัวไปข้างหลัง

สอดคล้อง? อนุญาตให้มีความทนทานเมื่อเผชิญกับการเปลี่ยนแปลงรหัสหรือไม่ การอ่าน?
Thomas Eding

1
ehhhh ฉันไม่มากแฟนของความคิดที่ว่าทุกความต้องการif elseโปรแกรมเมอร์คนสุดท้ายที่ทำงานกับ codebase ของเราตามมาอย่างเหนียวแน่น ( บางครั้ง ... มันเป็นโรคจิตเภท ) ด้วยเหตุนี้เราจึงมีelse { /* do nothing */ }บล็อกที่ไม่มีความหมายมากมายเกลื่อนรหัส ...
KChaloux

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

มันซ้ำซ้อนอย่างอื่น หากคุณกำลังทำงานกับ. NET stack มากกว่าติดตั้ง ReSharper และจะเตือนให้คุณลบคำสั่งที่ซ้ำซ้อนอื่นทั้งหมด
CodeART

คำตอบ:


16

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

อะไรที่ดูเหมือนว่าจะมากขึ้นหรือน้อยลงด้วยการที่ซิงเกิ้ลthrowจะกลายเป็นสิ่งที่น่าเกลียดอย่างแท้จริงเมื่อมีการเข้าประชิดหลายครั้งในการโยน:

void myMethod(int arg1, int arg2, int arg3) {
    // This is demonstrably ugly - do not code like that!
    if (!isValid(arg1)) {
        throw new ArgumentException("arg1 is invalid");
    } else {
        if (!isValid(arg2)) {
            throw new ArgumentException("arg2 is invalid");
        } else {
            if (!isValid(arg3)) {
                throw new ArgumentException("arg3 is invalid");
            } else {
                // The useful code starts here
            }
        }
    }
}

ตัวอย่างนี้ทำสิ่งเดียวกัน แต่มันดูดีกว่ามาก:

void myMethod(int arg1, int arg2, int arg3) {
    if (!isValid(arg1)) {
        throw new ArgumentException("arg1 is invalid");
    }
    if (!isValid(arg2)) {
        throw new ArgumentException("arg2 is invalid");
    }
    if (!isValid(arg3)) {
        throw new ArgumentException("arg3 is invalid");
    }
    // The useful code starts here
}

+1 จริง กรณี OP สองบังคับให้คุณอ่านอย่างระมัดระวังจากนั้นให้คุณใช้ WTF แต่ ... พยายามทำให้วิธีการสั้น ๆ อยู่เสมอ การกลับมาอยู่ตรงกลางของวิธี 200 บรรทัดก็ไม่ดีเช่นกัน
Tulains Córdova

1
else ifเพื่อความเป็นธรรมถ้าคุณเป็นเพียงการใช้ซ้ำถ้าคุณสามารถทำได้
Guvante

2
@Guvante: ifการทดสอบแต่ละครั้งสำหรับเงื่อนไขเดียวและจัดการกับมันหากเงื่อนไขเป็นจริงและถ้าไม่มีสิ่งอื่นที่จะเกิดขึ้นหากเงื่อนไขเป็นเท็จelse ifs ไม่จำเป็น เรามีคำศัพท์รอบ ๆ ออฟฟิศของฉันสำหรับรหัสเช่นตัวอย่างแรกของ dasblinkenlight: " เครื่องปาจิงโกะ "
Blrfl

@Blrfl เครื่องปาจิงโกะฮะการเปรียบเทียบที่สมบูรณ์แบบ +1
จิมมี่ฮอฟฟา

@Blrfl: ฉันอ้างว่าซ้ำ ifs เป็นตัวอย่างที่ดีของการทำรังมากเกินไป คุณไม่ควรทำรังซ้ำอีกต่อไป ผมเห็นว่าโดยทั่วไปจนกว่าคุณจะได้พูดคุยเกี่ยวกับจำนวนเงินที่เล็ก ๆ น้อย ๆ elseของรหัสมีเหตุผลที่จะไม่รวม
Guvante

5

ฉันจะเรียกวิธีปฏิบัติที่ "ชัดเจนอย่างอื่น" ที่คุณอ้างถึงว่าเป็นรูปแบบการต่อต้านเนื่องจากจะปิดบังความจริงที่ว่าไม่มีรหัสตัวพิมพ์พิเศษเป็นอย่างอื่นหากคุณ

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

พูดเช่นคุณมีฟังก์ชั่นนี้:

public void ConfigureOblogon(Oblogon oblogonToConfigure)
{
    if (_validColors.Contains(oblogonToConfigure.Color))
    {
        oblogonToConfigure.ColorIndex = _validColors.IndexOf(oblogonToConfigure.Color);
    }
    else
    {
        oblogonToConfigure.Color = _validColors[0];
        oblogonToConfigure.ColorIndex = 0;
    }
}

ตอนนี้ความต้องการมาในระหว่างการกำหนดค่าคุณควรระบุดัชนีประเภท / ประเภทของ oblogon มีหลายขอบเขตที่บางคนสามารถวางรหัสนั้นและท้ายด้วยรหัสที่ไม่ถูกต้องเช่น

public void ConfigureOblogon(Oblogon oblogonToConfigure)
{
    if (!_validOblogons.Contains(oblogonToConfigure.Type))
    {
        oblogonToConfigure.Type = _validOblogons[0];
        oblogonToConfigure.TypeIndex = 0;
        if (_validColors.Contains(oblogonToConfigure.Color))
        {
            oblogonToConfigure.ColorIndex = _validColors.IndexOf(oblogonToConfigure.Color);
        }
        else
        {
            oblogonToConfigure.Color = _validColors[0];
            oblogonToConfigure.ColorIndex = 0;
        }
    }
    else
    {
        oblogonToConfigure.TypeIndex = _validOblogons.IndexOf(oblogonToConfigure.Type);
    }
}

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

public void ConfigureOblogon(Oblogon oblogonToConfigure)
{
    if (!_validColors.Contains(oblogonToConfigure.Color))
    {
        oblogonToConfigure.Color = _validColors[0];
    }

    oblogonToConfigure.ColorIndex = _validColors.IndexOf(oblogonToConfigure.Color);
}

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

ฉันรู้ว่ามันเป็นตัวอย่างเล็กน้อย แต่ฉันได้เห็นหลายครั้ง

SomeFunction()
{
    if (isvalid)
    {
        /* ENTIRE FUNCTION */
    }
    /* Nothing should go here but something does on accident, and an invalid scenario is created. */
}

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

SomeFunction()
{
    if (!isvalid)
    {
        /* Nothing should go here, and it's so small no one will likely accidentally put something here */
        return;
    }

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