การใช้บล็อกขอบเขตภายในภายในฟังก์ชั่นมีสไตล์ไม่ดีหรือไม่?


10

มีบางกรณี (ค่อนข้างหายาก) ที่มีความเสี่ยง:

  • การนำตัวแปรที่ไม่ต้องการนำมาใช้ซ้ำ (ดูตัวอย่างที่ 1)

  • หรือใช้ตัวแปรแทนตัวแปรอื่นปิดความหมาย (ดูตัวอย่างที่ 2)

ตัวอย่างที่ 1:

var data = this.InitializeData();
if (this.IsConsistent(data, this.state))
{
    this.ETL.Process(data); // Alters original data in a way it couldn't be used any longer.
}

// ...

foreach (var flow in data.Flows)
{
    // This shouldn't happen: given that ETL possibly altered the contents of `data`, it is
    // not longer reliable to use `data.Flows`.
}

ตัวอย่างที่ 2:

var userSettingsFile = SettingsFiles.LoadForUser();
var appSettingsFile = SettingsFiles.LoadForApp();

if (someCondition)
{
    userSettingsFile.Destroy();
}

userSettingsFile.ParseAndApply(); // There is a mistake here: `userSettingsFile` was maybe
                                  // destroyed. It's `appSettingsFile` which should have
                                  // been used instead.

ความเสี่ยงนี้สามารถบรรเทาได้ด้วยการแนะนำขอบเขต:

ตัวอย่างที่ 1:

// There is no `foreach`, `if` or anything like this before `{`.

{
    var data = this.InitializeData();
    if (this.IsConsistent(data, this.state))
    {
        this.ETL.Process(data);
    }
}

// ...

// A few lines later, we can't use `data.Flows`, because it doesn't exist in this scope.

ตัวอย่างที่ 2:

{
    var userSettingsFile = SettingsFiles.LoadForUser();

    if (someCondition)
    {
        userSettingsFile.Destroy();
    }
}

{
    var appSettingsFile = SettingsFiles.LoadForApp();

    // `userSettingsFile` is out of scope. There is no risk to use it instead of
    // `appSettingsFile`.
}

มันดูผิดหรือเปล่า? คุณจะหลีกเลี่ยงไวยากรณ์ดังกล่าวหรือไม่ เป็นการยากที่จะเข้าใจโดยผู้เริ่มต้น?


7
คุณสามารถยืนยันว่าแต่ละ "บล็อกขอบเขต" อิสระแทนที่จะเป็นวิธีการหรือหน้าที่ของตัวเอง?
Dan Pichelman

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

คำตอบ:


35

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

เมื่อต้องการสำรองข้อมูลนี้ด้วยประสบการณ์ส่วนตัว: เมื่อหลายปีก่อนฉันได้รับมรดกโครงการ C ++ ด้วยรหัสบรรทัด ~ 150K และมีวิธีการสองสามอย่างที่ใช้เทคนิคนี้อย่างแน่นอน และเดาว่าอะไร - วิธีการทั้งหมดนั้นยาวเกินไป ในขณะที่เราปรับโครงสร้างโค้ดส่วนใหญ่ใหม่วิธีการก็เล็กลงและเล็กลงและฉันค่อนข้างมั่นใจว่าไม่มีวิธี "ขอบเขตภายใน" ที่เหลืออยู่อีกต่อไป พวกเขาไม่ต้องการ


4
แต่ทำไมมันถึงไม่ดี? การมีฟังก์ชั่นที่ตั้งชื่อไว้จำนวนมากก็สร้างความสับสนเช่นกัน
Kris Van Bael

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

10
@KrisVanBael: "การมีฟังก์ชั่นที่ตั้งชื่อไว้มากมายนั้นทำให้เกิดความสับสน" - หากคุณใช้ชื่อที่สื่อความหมาย การสร้างฟังก์ชั่นที่มีขนาดใหญ่เกินไปนั้นเป็นเหตุผลสูงสุดที่ว่าโค้ดนั้นยากที่จะรักษาและยิ่งยากที่จะขยายขอบเขต
Doc Brown

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

3
ยังไม่มั่นใจ ฟังก์ชั่นที่ยาวนานมักไม่ดีอย่างแน่นอน แต่การบอกว่าทุกความต้องการในขอบเขตจำเป็นต้องมีฟังก์ชั่นแยกต่างหากคือขาวดำสำหรับฉัน
Kris Van Bael

3

มันง่ายกว่ามากสำหรับผู้เริ่มต้น (และโปรแกรมเมอร์) ที่จะคิดถึง:

  • ไม่ใช้ตัวแปรที่ไม่เกี่ยวข้อง

กว่าที่จะคิด:

  • การเพิ่มโครงสร้างโค้ดโดยมีวัตถุประสงค์เพื่อป้องกันตัวเองจากการไม่ใช้ตัวแปรที่ไม่เกี่ยวข้อง

ยิ่งไปกว่านั้นจากมุมมองของผู้อ่านบล็อกดังกล่าวไม่มีบทบาทที่ชัดเจน: การลบบล็อกดังกล่าวไม่มีผลกระทบต่อการดำเนินการ ผู้อ่านอาจเกาหัวของเขาพยายามคาดเดาสิ่งที่ coder ต้องการบรรลุ


2

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


0

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

มีสถานการณ์หนึ่งโดยเฉพาะคือ OTOH ใน C # เมื่อพวกเขามีแนวโน้มที่จะป๊อปอัพ - นั่นคือเมื่อใช้การสร้างกรณีสวิตช์ สถานการณ์ได้รับการอธิบายอย่างดีใน: คำสั่ง C # Switch ที่มี / ไม่มีวงเล็บปีกกา…อะไรคือความแตกต่าง?

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