C # namespace และแบบแผนการตั้งชื่อคลาสสำหรับไลบรารี


26

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

Company
Company.TextUtils
    public class TextUtils {...}
Company.MathsUtils
    public class MathsUtils {...}
    public class ArbitraryPrecisionNumber {...}
    public class MathsNotation {...}
Company.SIUnits
    public enum SISuffixes {...}
    public class SIUnits {...}

นี่เป็นวิธีที่ดีในการจัดระเบียบเนมสเปซและคลาสหรือมีวิธีที่ดีกว่านี้หรือไม่? โดยเฉพาะดูเหมือนว่ามีชื่อเดียวกันในเนมสเปซและชื่อคลาส (เช่นCompany.TextUtilsเนมสเปซและTextUtilsคลาส) เป็นเพียงการทำซ้ำและแสดงให้เห็นว่ารูปแบบอาจดีกว่า



5
หลักเกณฑ์ของ Microsoft แนะนำชื่อเอกพจน์สำหรับ enums (ดังนั้นSISuffixแทนที่จะเป็นSISuffixes) และฉันคิดว่าเอกพจน์อ่านได้ดีกว่า Suffix.A อ่านว่า "คำต่อท้าย A" นอกจากนี้ฉันมักหลีกเลี่ยงชื่อซ้ำจากระดับขึ้นไปในลำดับชั้น นั่นคือแทนที่จะCompany.SIUnits.SISuffixesฉันจะโน้มตัวไปข้างหน้าCompany.SI.SuffixและCompany.SI.Unit
แฮร์ริสันพายน์

คำตอบ:


9

เป็นการยากมากที่จะพิจารณาว่ากลยุทธ์การตั้งชื่อของคุณมีประสิทธิภาพแยกจากส่วนที่เหลือของรหัสของคุณอย่างไร

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

ในตัวอย่างเฉพาะของคุณหากคุณมีคลาสประเภท 'Util' มากขึ้นฉันจะลองวางมันไว้ใต้Company.Utils.Mathsนั้นด้วยวิธีนี้ถ้าคุณต้องการเพิ่มฟังก์ชั่นที่ใช้ร่วมกับพื้นที่สาธารณูปโภคหลายแห่งคุณมีอยู่แล้ว สถานที่ธรรมชาติสำหรับมัน


1
ฟังดูเหมือนความคิดที่ดี หยุดความกังวลมากเกินไปเพียงทำทุกอย่างให้เป็น "Company.Util"
ผู้ใช้

30

: มีเอกสารที่ดีที่มีจำนวนมากของกฎที่คุณควรปฏิบัติตามเพื่อให้สอดคล้องกับไมโครซอฟท์เป็นแนวทางการออกแบบกรอบ

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


3
การเชื่อมโยงโดยตรงกับแนวทาง namespaces: msdn.microsoft.com/en-us/library/ms229026(v=vs.110).aspx
Pagotti

1
ซึ่งโดยบังเอิญหรือไม่ก็เป็นชื่อเดียวกันของหนังสือเล่มใหญ่ในเรื่องนี้เขียนโดยคน Microsoft ที่เข้าร่วมในการสร้างกรอบการทำงานของ DotNet พร้อมด้วยข้อสังเกตหลายประการเกี่ยวกับสิ่งที่พวกเขาทำถูกและผิดที่ คุ้มค่ากับการอ่าน: amazon.com/Framework-Design-Guidelines-Conventions-Library/dp/…
Machado

@nvoigt คุณสามารถแก้ไขคำตอบของคุณเพื่อเพิ่มคำพูดจากลิงก์ที่เพื่อนของเรา Pagotti จัดไว้ให้: " อย่าใช้ชื่อเดียวกันสำหรับเนมสเปซและประเภทในเนมสเปซนั้นตัวอย่างเช่นห้ามใช้ Debug เป็นชื่อเนมสเปซและ จากนั้นจัดเตรียมคลาสที่ชื่อ Debug ในเนมสเปซเดียวกันคอมไพเลอร์หลายตัวต้องการประเภทดังกล่าวเพื่อผ่านการรับรองโดยสมบูรณ์ "
Machado

2
Caveat: บางครั้งชื่อผลิตภัณฑ์ดีกว่าการใช้ชื่อ บริษัท รับในบางสถานการณ์ที่ บริษัท ถูกซื้อออกมาและเราต้องผลิตเนมสเปซใหม่ทั่วทั้งบอร์ดและรีลีสใหม่ ฉันคิดว่านี่มันน้อยมาก แต่ต้องการที่จะชี้ให้เห็น
Jon Raynor

1
แนวทางการออกแบบกรอบงานของ Microsoft เป็นที่น่าสงสัยอย่างมากมีคำแถลงเท็จเกี่ยวกับการทำงานของ. NET แนวทางการตั้งชื่อของพวกเขาดี แต่ฉันจะหลีกเลี่ยงการเชื่อมโยงแนวทางโดยรวมกับข้อความว่า "คุณควรปฏิบัติตาม"
Carl Leth

6

เป็นเวลานานแล้วที่ฉันทำงานกับ C # หรือ. NET systems ฉันจึงไม่สามารถบอกได้ว่าแนวทางปฏิบัติที่ดีที่สุดที่แนะนำในปัจจุบันคืออะไร ฉันขอแนะนำให้คุณเปลี่ยนชื่อของคุณเช่นนี้:

Company
Company.Text
    public class TextUtils {...}
Company.Math
    public class MathUtils {...}
    public class ArbitraryPrecisionNumber {...}
    public class MathsNotation {...}
Company.SI
    public enum SISuffixes {...}
    public class SIUnits {...}

สิ่งที่ฉันทำที่นี่คือ "Utils" ลบออกจากชื่อ namespace ฉันคิดว่า "Util" ไม่ควรอยู่ในเนมสเปซเพราะCompany.Textวันหนึ่งเนมสเปซอาจมีคลาสที่ไม่ใช่คลาสยูทิลิตี้ข้อความ Company.Mathnamespace แล้วมีArbitraryPrecisionNumberซึ่งดูเหมือนจะไม่เป็น "ยูทิลิตี้"

การลบ "Util" ออกจาก namespace จะกำจัดความสับสนที่อาจเกิดขึ้นโดยมีสองสิ่งที่มีชื่อเดียวกัน (ดังที่ได้กล่าวไว้ในคำตอบของ Robert: https://softwareengineering.stackexchange.com/a/340440/13156 )

อีกวิธีหนึ่งที่คุณสามารถจัดระเบียบโค้ดได้:

Company
Company.Util
    public class TextUtils {...}
    public class MathUtils {...}
Company.Math
    public class ArbitraryPrecisionNumber {...}
    public class MathsNotation {...}
Company.SI
    public enum SISuffixes {...}
    public class SIUnits {...}

ในกรณีนี้คลาสยูทิลิตี้ทั้งหมดจะอยู่ในเนมสเปซเดียวกัน ไม่มีCompany.Textเนมสเปซอีกต่อไปเนื่องจากสิ่งเดียวเท่านั้นที่มีคลาสยูทิลิตี้

โดยส่วนตัวแล้วฉันพบว่าตัวเลือกแรกค่อนข้างชัดเจนกว่า


4

การใช้ชื่อเดียวกันสำหรับเนมสเปซและคลาสที่อยู่ภายในนั้นเป็นปัญหา

  • หากเนมสเปซมีมากกว่าหนึ่งคลาสทำไมคลาสอื่น ๆ ถึงต้องอยู่ที่นั่น? มันไม่ถูกต้องเพราะเป้าหมายของชื่อของเนมสเปซคือการอธิบายคลาสทั้งหมดที่อยู่ภายในไม่ใช่เพียงแค่คลาสเดียว ตัวอย่างเช่นถ้าคุณมีJsonSerialization, BinarySerializationและXmlSerializationชั้นเรียนใน namespace ก็จะทำให้รู้สึกถึงชื่อ namespace ของคุณXmlSerialization?

    สิ่งที่มักจะเกิดขึ้นคือเนื่องจากการแยกคลาสออกจากเนมสเปซที่มีอยู่หรือการผสานระหว่างหลายคลาสหรือการปรับโครงสร้างองค์กรอื่นคุณพบว่าคุณมีเนมสเปซที่มีคลาสหลัก ก้าวหน้าชั้นเรียนเล็ก ๆ น้อย ๆ จะถูกวางไว้เพราะพวกเขามีความสัมพันธ์เล็กน้อยกับชั้นเรียนเดิม ตัวอย่างเช่นเนมสเปซLogParserอาจมีคลาสเดียวLogParserแล้วมีใครบางคนใส่LogConverterเพราะมันค่อนข้างเกี่ยวข้องกับ parser แล้วLogSearcherฯลฯ ปัญหาที่นี่คือชื่อของเนมสเปซไม่เปลี่ยน: ทันทีที่LogConverterถูกเพิ่มเข้ามา ชื่อควรจะมีการเปลี่ยนแปลงหรือเพียงLogsProcessingLogs

  • หากเนมสเปซมีเพียงคลาสเดียวอาจเป็นสัญญาณของปัญหาภายในการจัดระเบียบรหัส

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

    แม้ว่าเนมสเปซของคุณจะมีเพียงคลาสเดียว แต่โดยทั่วไปจะมีวิธีที่เฉพาะเจาะจงมากขึ้นเมื่อตั้งชื่อคลาสและโดยทั่วไปเมื่อตั้งชื่อ namespace ลองนึกภาพแอปพลิเคชั่นที่ควรแปลงไฟล์ที่เขียนในรูปแบบ ABC เป็นรูปแบบ DEF การแปลงไม่จำเป็นต้องมีการดีซีเรียลไลซ์เซชั่น / การทำให้เป็นอนุกรมจาก / วัตถุทางธุรกิจและทำได้โดยการใช้การแสดงออกปกติจำนวนมากซึ่งสั้นพอที่จะใส่ในคลาสการแปลงเองที่เรียกว่าAbcToDefConverter. ตรรกะการแปลงทั้งหมดใช้เวลาประมาณ 80 LLOC ในวิธีการพึ่งพาซึ่งกันและกันประมาณสิบวิธี - ดูเหมือนว่าสถานการณ์ที่ไม่จำเป็นต้องแยกชั้นที่มีอยู่หรือสร้างชั้นเรียนเพิ่มเติม เนื่องจากส่วนที่เหลือของแอปพลิเคชันไม่มีส่วนเกี่ยวข้องกับการแปลงคลาสจึงไม่สามารถจัดกลุ่มกับคลาสอื่นในเนมสเปซที่มีอยู่ได้ ดังนั้นหนึ่งสร้าง namespace AbcToDefConverterที่เรียกว่า Convertersขณะที่มีอะไรผิดปกติในเนื้อแท้ที่หนึ่งยังสามารถใช้ชื่อทั่วไปมากขึ้นเช่น ในภาษาเช่น Python ที่ต้องการชื่อที่สั้นกว่าและมีการใช้คำซ้ำซ้ำไปซ้ำconverters.Abc_To_Defมา

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


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

การตั้งชื่อมีเหตุผล: เพื่อทำให้ชีวิตของคุณง่ายขึ้นเมื่อคุณต้องการค้นหาสิ่งต่าง ๆ ในภายหลัง คุณรู้ว่าถ้าคุณต้องการวาดแผนภูมิคุณอาจลองค้นหา "แผนภูมิ" หรือ "พล็อต" เมื่อคุณต้องการเปลี่ยนวิธีที่แอปสร้างใบแจ้งหนี้คุณจะค้นหา "ใบแจ้งหนี้ [e / ing]" หรือ "ใบเรียกเก็บเงิน" ในทำนองเดียวกันลองจินตนาการถึงกรณีที่คุณจะพูดกับตัวเองว่า: "หืมมมคุณลักษณะนี้น่าจะพบได้บ่อย" ฉันทำไม่ได้

ดู. NET Framework คลาสยูทิลิตี้คลาสเหล่านั้นไม่ได้ใช่หรือไม่ ฉันหมายความว่าพวกเขามีบางสิ่งที่ต้องทำกับโดเมนธุรกิจ ถ้าฉันทำงานในแอพทางการเงินหรือเว็บไซต์อีคอมเมิร์ซหรือแพลตฟอร์มการศึกษาต่อไปการทำให้เป็นอันดับ XML หรือการอ่านไฟล์หรือทำแบบสอบถาม SQL หรือการทำธุรกรรมเป็นสิ่งที่ยูทิลิตี้ทั้งหมด อย่างไรก็ตามพวกเขาไม่ได้เรียกUtilitySerializationหรือหรือUtilityTransactionพวกเขาไม่ได้อยู่ในUtilitynamespace พวกเขามีชื่อที่เหมาะสมซึ่งทำให้เป็นไปได้ (และง่ายขอบคุณนักพัฒนา. NET!) เพื่อค้นหาพวกเขาเมื่อฉันต้องการ

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

ลองนึกภาพคุณสร้างรหัสบางส่วนที่เกี่ยวข้องกับหน่วยและการแปลงหน่วย คุณอาจตั้งชื่อUtilityและเกลียดชังโดยเพื่อนร่วมงานของคุณ หรือคุณอาจจะชื่อมันและUnitsUnitsConversion


7
"คลาสยูทิลิตี้ผิดโดยธรรมชาติ" น่าสนใจ คุณเสนอวิธีแก้ปัญหาสำหรับอะไรเช่นคลาสยูทิลิตี้ฟังก์ชันคณิตศาสตร์? ควรอินสแตนซ์ของวัตถุคณิตศาสตร์จริงๆมีความจำเป็นที่จะใช้ฟังก์ชั่นเกินกว่าผู้ประกอบการทางคณิตศาสตร์ขั้นพื้นฐาน?
FrustratedWithFormsDesigner

1
ฉันเห็นด้วยกับคุณ แต่สิ่งที่คุณแนะนำเป็นทางเลือก?
ผู้ใช้


4
ฉันล่าช้าในการสร้างไลบรารี่ "utils" เป็นเวลานาน แต่ในที่สุดคุณก็ต้องยอมแพ้ทางเลือกคือ DLLs ประกอบด้วยโค้ดประมาณ 3 บรรทัดซึ่งยุ่งยากมาก (และทำให้ฉันสับสนกับการพึ่งพาโหนด ) หรือคัดลอกและวางวิธีการยูทิลิตีของคุณไปยังทุก ๆ คลาสที่อาจจำเป็นต้องใช้ (เพื่อหลีกเลี่ยงการมีคลาส "คอลเลกชันของวิธีการแบบสุ่ม") IMO ในที่สุดมันเป็นความชั่วร้ายที่จำเป็น
Matti Virkkunen

3
@FrustratedWithFormsDesigner: เพียงแค่ ... Math? ฉันไม่เห็นว่าการUtilityต่อท้ายทุกสิ่งจะทำให้ชีวิตของเราง่ายขึ้นได้อย่างไร เมื่อใช้System.Math.Min()เมธอดของ. NET คุณต้องการเขียนSystemUtility.MathUtility.Min()แทนจริงๆหรือไม่? ในทุกกรณีฉันแก้ไขคำตอบของฉันอย่างหนักดังนั้นจึงควรชัดเจนกว่านี้
Arseni Mourzenko
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.