แนวทางปฏิบัติที่ดีที่สุดสำหรับการใช้เนมสเปซใน C ++ [ปิด]


38

ฉันได้อ่านClean Codeของลุงบ็อบเมื่อสองสามเดือนที่ผ่านมาและมันมีผลกระทบอย่างลึกซึ้งต่อวิธีการเขียนโค้ดของฉัน แม้ว่าดูเหมือนว่าเขาจะทำซ้ำสิ่งที่โปรแกรมเมอร์ทุกคนควรรู้การรวมพวกเขาทั้งหมดเข้าด้วยกันและนำพวกเขาไปสู่การปฏิบัติจะส่งผลให้มีโค้ดที่สะอาดกว่ามาก โดยเฉพาะอย่างยิ่งฉันพบว่าการแบ่งฟังก์ชั่นขนาดใหญ่ออกเป็นฟังก์ชั่นขนาดเล็กจำนวนมากและการแบ่งคลาสขนาดใหญ่เป็นคลาสจิ๋วจำนวนมากเพื่อให้มีประโยชน์อย่างเหลือเชื่อ

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

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

แก้ไข: คำถามของฉันเป็นคำตอบในเรื่องนี้รายการวิกิพีเดียเกี่ยวกับแพคเกจหลักการ


7
ตัวอย่างของดีอีกและคำถามนักพัฒนาที่แท้จริงของโลกปิด หากนี่ไม่ใช่ไซต์ stackexchange ที่ถามเกี่ยวกับแนวทางปฏิบัติที่ดีที่สุดของนักพัฒนา
Sam Goldberg

@ SamGoldberg: มันดีขึ้น ผมพบคำตอบที่ดีสำหรับคำถามนี้ที่นี่: en.wikipedia.org/wiki/Package_Principles ฉันโพสต์คำตอบนี้และผู้ดำเนินการลบออกเพราะฉันโพสต์ลิงค์และไม่มีเวลาในการคัดลอก / วางเนื้อหา
Dima

1
ฉันคิดว่าการวิจารณ์คำถามเดียวของฉันคือแทนที่จะถามคำถามหลายข้อในตอนท้ายพยายามสรุปคำถามนั้นเป็นคำถามเดียวเช่น "สิ่งที่ควรเป็นเกณฑ์ในการพิจารณาว่ารายการควรอยู่ในเนมสเปซเดียวกันหรือเนมสเปซต่างกันหรือไม่ "
Sam Goldberg

คำตอบ:


22

(ฉันยังไม่ได้อ่านClean Codeและไม่รู้ Java มาก)

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

ใช่เช่นเดียวกับที่มีการปรับโครงสร้างใหม่ในหลาย ๆ คลาสและหลายฟังก์ชั่น

กลุ่มเล็ก ๆ ของคลาสที่เกี่ยวข้องควรถูกห่อในเนมสเปซหรือไม่?

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

กลุ่มเล็ก ๆ ของคลาสที่เกี่ยวข้องควรถูกห่อในเนมสเปซที่อุทิศให้กับพวกเขาหรือไม่? อาจ. โดยเฉพาะอย่างยิ่งถ้าคุณพบว่าตัวเองใช้คำนำหน้าทั่วไปในคลาสเหล่านั้น - FrobberThing, FrobberThang, FrobberDoohickey - คุณควรพิจารณา namespace - frobber :: Thing เป็นต้น สิ่งนี้จะยังคงอยู่ภายใต้รูทเนมสเปซของคุณหรือเนมสเปซอื่นหากเป็นส่วนหนึ่งของโครงการขนาดใหญ่

นี่เป็นวิธีการจัดการความซับซ้อนของการมีคลาสเล็ก ๆ จำนวนมากหรือค่าใช้จ่ายในการจัดการเนมสเปซมากมายเป็นสิ่งต้องห้ามหรือไม่?

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

นามแฝงของนามแฝงอนุญาตให้คุณใช้ชื่อที่สั้นกว่าสำหรับเนมสเปซที่ยาวขึ้นในบริบทเฉพาะซึ่งอนุญาตให้ใช้งานได้ง่ายขึ้นอีกครั้ง:

void f() {
  namespace CWVLN = Company_with_very_long_name;  // Example from the standard.
  // In this scope, use CWVLN::name instead of Company_with_very_long_name::name.
  namespace fs = boost::filesystem;  // Commonly used.
}

พิจารณา Boost ซึ่งมีเนมสเปซรูทเดียวเพิ่มและจากนั้นหลายชื่อย่อย - เพิ่ม :: asio, เพิ่ม :: io, เพิ่ม :: ระบบไฟล์, เพิ่ม :: tuples, ฯลฯ - สำหรับไลบรารีต่างๆ ชื่อบางชื่อ "เลื่อน"เป็นรูทเนมสเปซ:

คำจำกัดความทั้งหมดอยู่ใน namespace :: boost :: tuples แต่ชื่อทั่วไปส่วนใหญ่จะถูกยกไปที่ namespace :: boost ด้วยการใช้การประกาศ ชื่อเหล่านี้คือ: tuple, make_tuple, tie และ get นอกจากนี้ ref และ cref ถูกกำหนดโดยตรงภายใต้ :: boost namespace

ความแตกต่างที่ใหญ่ที่สุดจากภาษาที่มีโมดูล "ของจริง" คือวิธีการทั่วไปที่จะใช้โครงสร้างอี๋ที่เกิดขึ้นเพราะส่วนใหญ่มันเป็นวิธีการทำงานเว้นแต่คุณจะใช้ความพยายามพิเศษในการกำหนดชื่อที่ซ้อนกัน


+1 @Fred Nurk สำหรับการวิเคราะห์แบบเต็มแทนที่จะเป็นหนึ่งคำตอบ คุณไม่ต้องอ่านหนังสือเพื่อรู้ว่าคำถามนั้นเกี่ยวกับอะไร เธรดความคิดเห็นนี้แสดงถึงแนวคิดและความแตกต่างที่ C ++ และโปรแกรมเมอร์ Java อาจมีอยู่ในหนังสือเล่มนี้ ทำความสะอาดรหัสความคิดเห็นใน Amazon
Marlon

8

คุณควรมีเนมสเปซหลักหนึ่งอันสำหรับรหัสทั้งหมดของคุณ สิ่งนี้แตกต่างจากรหัสภายนอกที่เกี่ยวข้องกับเนมสเปซ

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

โดยเฉพาะอย่างยิ่งถ้าคุณมีชื่อที่ทำให้เกิดเสียงทั่วไปเช่น FileInfo ซึ่งหมายถึงบางสิ่งเฉพาะภายในบริบทให้ใส่ไว้ในเนมสเปซ

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


3

Namespaces ไม่ใช่แนวคิดของโมดูลดังนั้นฉันจะใช้เฉพาะในกรณีที่ความขัดแย้งของชื่อเกิดขึ้น


4
ไม่แน่ใจว่าคุณหมายถึงอะไร. เหตุใดชุดคลาสที่เกี่ยวข้องที่ห่อในเนมสเปซจะไม่เป็นโมดูล
Dima

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

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

3
การ จำกัด การเข้าถึงเป็นแบบฉากกับโมดูล ในความเป็นจริงคุณมีระบบที่ประสบความสำเร็จเช่น Python ซึ่งแน่นอนว่าเป็น "โมดูลเหมือน" มากกว่า namespaces ของ C ++ แต่ไม่มีข้อ จำกัด การเข้าถึงเลย
Fred Nurk

ฉันเชื่อว่านี่เป็นหนึ่งในแนวทางปฏิบัติที่ดีที่สุดที่ระบุไว้ในหนังสือของ Scott Meyer
Raphael

1

Java มีเนมสเปซ แต่พวกเขาก็ไม่ได้เรียกอย่างนั้นจริงๆ In javax.swing.* javaxคือเนมสเปซและswingเป็นเนมสเปซย่อย ฉันไม่ได้อ่านหนังสือเล่มนี้เพื่อรู้ว่ามันพูดอะไรเกี่ยวกับแพ็คเกจ Java แต่หลักการเดียวกันนี้จะนำไปใช้กับเนมสเปซในภาษาใด ๆ ได้โดยตรง

ฮิวริสติกที่ดีคือคุณใช้เนมสเปซเมื่อคุณพบว่าคุณต้องการพิมพ์คำนำหน้าเหมือนกันสำหรับชั้นเรียนซ้ำไปซ้ำมา ตัวอย่างเช่นฉันเพิ่งเขียนบางคลาสที่เรียกว่า OmciAttribute, OmciAlarm, OmciMe ฯลฯ และรู้ว่าฉันต้องแบ่ง Omci ลงในเนมสเปซของตัวเอง


1

ฉันชอบเนมสเปซลึก ๆ (ซึ่งมักจะหมายถึงสามระดับ)

  • ฉันมีชื่อ บริษัท
  • app / util / lib / ฯลฯ
  • ชื่อโครงการหรือแพ็คเกจตามความเหมาะสม

ขึ้นอยู่กับสถานการณ์ฉันอาจมีอีกระดับหนึ่ง

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