หลายคลาสที่มีชื่อเดียวกัน แต่มีเนมสเปซที่แตกต่างกันใช่ไหม


11

ฉันพบรหัสบางส่วน (C # ถ้าสำคัญ) ที่มีคลาสที่มีชื่อเหมือนกัน แต่แตกต่างกันในเนมสเปซ พวกเขาทั้งหมดมีแนวโน้มที่จะเป็นตัวแทนของสิ่งเดียวกัน แต่มักจะ "มุมมอง" ที่แตกต่างกันของวัตถุเดียวกัน เนมสเปซที่แตกต่างกันนั้นเป็นส่วนหนึ่งของโซลูชันเดียวกันและแม้แต่ dll เดียวกัน

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

คำถามเกี่ยวกับการตั้งชื่อ smurfสัมผัสนี้ แต่จากทิศทางอื่น การแก้ความสงสัยในชื่ออาจต้องการคำนำหน้าโดยพลการและแพร่หลายซึ่งคำถามนั้นต้องการกำจัด

แนวทางการปฏิบัตินี้มีอะไรบ้าง?


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

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

@JohnGaughan - พิจารณาEmployeeเป็นตัวอย่าง มีพนักงานที่มีไว้สำหรับพนักงานคนอื่น ๆ คนหนึ่งสำหรับทรัพยากรบุคคลหนึ่งคนสำหรับการสัมผัสภายนอก พวกเขาทั้งหมดมีชื่อว่า "ลูกจ้าง" และพวกเขาล้วนมีผู้ช่วยเหลือหลากหลาย (EmployeeRepository, EmployeeView และอื่น ๆ ) พวกเขาทั้งหมดอยู่ใน dll เดียวกันและในขณะที่พวกเขาแบ่งปันคุณสมบัติทั่วไปบางอย่าง (ชื่อชื่อ) พวกเขาทั้งหมดแตกต่างกัน (หมายเลขโทรศัพท์เงินเดือน)
Telastyn

การทำงานร่วมกับระบบที่รุ่นEmployees หลายครั้งเสียงเหมือนคุณต้องการรูปแบบที่มีสหภาพของคุณลักษณะทั้งหมดและรวมถึงtypeหรือdepartmentแอตทริบิวต์ มิฉะนั้นจะไม่มีการซ้ำซ้อนของรหัส

5
นี่เป็นสาเหตุหนึ่งที่ทำให้เนมสเปซเริ่มต้นด้วยใช่หรือไม่ หากต้องการอนุญาตการชนชื่อ
Dan Pichelman

คำตอบ:


5

ฉันจะพยายามให้คำตอบกับการใช้งานดังกล่าวหลังจากได้เห็นและทำงานเกี่ยวกับเรื่องนี้ในโครงการของฉันเช่นกัน

อ่านรหัสได้

ก่อนอื่นให้พิจารณาว่าการอ่านรหัสมีความสำคัญและการปฏิบัตินี้ตรงกันข้ามกับที่ doSomething(Employee e)มีคนอ่านชิ้นส่วนของรหัสและขอเพียงแค่บอกว่ามันมีฟังก์ชั่น สิ่งนี้ไม่สามารถอ่านได้อีกต่อไปเนื่องจากมี 10 Employeeคลาสที่แตกต่างกันที่มีอยู่ในแพ็คเกจที่แตกต่างกันคุณจะต้องทำการประกาศการนำเข้าก่อนเพื่อค้นหาว่าข้อมูลของคุณคืออะไร

อย่างไรก็ตามนี่คือมุมมองระดับสูงและบ่อยครั้งที่เรามีการสุ่มชื่อที่ดูเหมือนว่าไม่มีใครสนใจหรือพบเพราะความหมายสามารถได้มาจากรหัสที่เหลือและแพ็คเกจที่คุณอยู่ดังนั้นเราจึงอาจโต้แย้ง ภายในนั้นไม่มีปัญหาเพราะแน่นอนถ้าคุณเห็นEmployeeในhrแพ็คเกจคุณต้องรู้ว่าเรากำลังพูดถึงมุมมอง HR ของพนักงาน

สิ่งต่าง ๆ แตกสลายทันทีที่คุณออกจากแพ็คเกจเหล่านี้ เมื่อคุณทำงานในโมดูล / แพ็คเกจ / อื่น ๆ ที่แตกต่างกันและจำเป็นต้องทำงานกับพนักงานคุณกำลังเสียสละความสามารถในการอ่านหากคุณไม่ได้มีคุณสมบัติครบถ้วนประเภท นอกจากนี้การมี 10 Employeeคลาสที่แตกต่างกันหมายความว่าการเติมข้อมูลอัตโนมัติของ IDE จะไม่ทำงานอีกต่อไปและคุณต้องเลือกจากประเภทพนักงานด้วยตนเอง

การทำสำเนารหัส

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

ความซับซ้อนของรหัส

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

การสื่อสารรหัส

นอกเหนือจากปัญหาข้างต้นที่มีความซับซ้อนของรหัสซึ่งเกี่ยวข้องกับตัวเลือกการออกแบบคุณยังลดความชัดเจนของการออกแบบระดับสูงขึ้นและสูญเสียความสามารถในการสื่อสารกับผู้เชี่ยวชาญด้านโดเมนอย่างถูกต้อง given an employee, you can do ...เมื่อคุณหารือเกี่ยวกับสถาปัตยกรรมการออกแบบหรือความต้องการของคุณจะไม่มีอิสระที่จะทำให้งบง่ายๆเช่น นักพัฒนาจะไม่ทราบว่าemployeeจริงๆแล้วมีความหมายในตอนนี้ แม้ว่าผู้เชี่ยวชาญด้านโดเมนจะรู้แน่นอน เราทุกคนทำ ประเภทของ แต่ในแง่ของซอฟต์แวร์มันไม่ง่ายที่จะสื่อสารอีกต่อไป

วิธีกำจัดปัญหา

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

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

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

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

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


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

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

หากมีการใช้หลายคลาสที่มีชื่อเดียวกันในบริบทเดียวกันแสดงว่าเป็นเรื่องยาก ฉันไม่เห็นกรณีนั้น ฉันเคยเห็นหลายคลาสที่มีชื่อเหมือนกัน แต่ไม่ได้ใช้บ่อยในบริบทเดียวกับที่คุณพูดถึง
InformAA

@randomA - น่าเศร้าที่กรณีนี้เป็นเรื่องธรรมดาใน codebase นี้
Telastyn

จุดดี แต่คุณยังไม่ได้ให้วิธีการแก้ปัญหาหลักวิธีการเฉพาะเมื่อปัญหาหลักได้รับการแก้ไข ("สิ่งที่พนักงานจริงๆคือ") "โซลูชัน" ที่ชัดเจนเพียงอย่างเดียว ("รวมคุณสมบัติทั้งหมดของแต่ละบุคคลไว้ในพนักงานพระเจ้าคนเดียว") ที่คุณทิ้งไปอย่างถูกต้อง สมมติว่าคุณมี DB.Employee, Marshalling.Employee, ViewModels.Employee, GUI.Views.Employee และอื่น ๆ โซลูชันของคุณคืออะไร
Pablo H

9

Scala Collection Framework เป็นตัวอย่างที่ดีของเรื่องนี้ มีคอลเลกชันที่ไม่แน่นอนและไม่เปลี่ยนรูปแบบเช่นเดียวกับคอลเลกชันอนุกรมและขนาน (และในอนาคตอาจจะกระจายเช่นกัน) คอลเลกชัน ตัวอย่างเช่นมีสี่Mapลักษณะ:

scala.collection.Map
scala.collection.immutable.Map
scala.collection.mutable.Map
scala.collection.concurrent.Map

บวกสามParMapวินาที:

scala.collecion.parallel.ParMap
scala.collecion.parallel.immutable.ParMap
scala.collecion.parallel.mutable.ParMap

น่าสนใจยิ่งขึ้น:

scala.collection.immutable.Map            extends scala.collection.Map
scala.collection.mutable.Map              extends scala.collection.Map
scala.collection.concurrent.Map           extends scala.collection.mutable.Map

scala.collecion.parallel.ParMap           extends scala.collection.Map
scala.collecion.parallel.immutable.ParMap extends scala.collecion.parallel.ParMap
scala.collecion.parallel.mutable.ParMap   extends scala.collecion.parallel.ParMap

ดังนั้นParMapขยายParMapขยายMapและMapขยายMapMapขยาย

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


3
"นั่นคือสิ่งที่ namespaces สำหรับ!" => +1
svidgen

ฉันชอบสิ่งนี้ แต่ในโลก C # /. NET เมื่อฉันย้ายคลาสแบบขนานไปยัง Parallel Sub-namespace สิ่งนี้จะเกิดการปะทะกับคลาส Helper System.Threading.Parallel ซึ่งฉันใช้อย่างหนักเพื่อให้ได้ความขนาน ฉันไม่ต้องการใช้เนมสเปซ 'พร้อมกัน' แทนเนื่องจากมันถูกใช้เพื่อหมายถึง 'การเข้าถึงพร้อมกัน' ในคลาสคอลเลกชัน ในฐานะที่เป็นผู้ประนีประนอมฉันได้เลือกใช้ sub-namespace 'Parallelized'
redcalx

2

นี่เป็นคำถามที่น่าสนใจจริง ๆ ซึ่งทั้งสองคำตอบที่ตรงข้ามกับคำตอบนั้นถูกต้องทั้งคู่ นี่คือตัวอย่างจริงของโลกของการสนทนานี้ที่เรามีในโครงการของฉัน

ฉันคิดว่ามีข้อควรพิจารณาที่สำคัญสองข้อที่จะทำให้คุณอยากไปในทิศทางเดียวหรืออีกทิศทางหนึ่งโดยดึงคำตอบทั้งสองจาก @Jorg และ @Frank:

  1. หากคุณคาดการณ์สถานการณ์ที่อาจต้องใช้คลาสที่มีชื่อเดียวกันมากกว่าหนึ่งรายการภายในบริบทรหัสเดียวกันนี่คือเหตุผลที่จะไม่ใช้ชื่อเดียวกัน นั่นคือถ้าคุณต้องทำงานด้วยhr.Employeeแต่ในเวลาเดียวกันจำเป็นต้องดูสิทธิ์ผ่านsecurity.Employeeมันจะได้รับความรวดเร็วอย่างแท้จริงที่น่ารำคาญ
  2. ในทางกลับกันหากคลาสของคุณที่มีชื่อเดียวกันมี API เดียวกันหรือคล้ายกันมากแสดงว่าเป็นตัวอย่างที่ดีที่คุณควรใช้ชื่อเดียวกันกับเนมสเปซที่ต่างกัน ตัวอย่าง Scala เป็นเช่นนี้โดยที่ทุกMapคลาสใช้อินเทอร์เฟซเดียวกันหรือเป็นคลาสย่อยของกันและกัน ในกรณีนี้ความคลุมเครือหรือ "ความสับสน" สามารถเรียกได้ว่าเป็นสิ่งที่ดีเพราะผู้ใช้สามารถปฏิบัติตามการใช้งานทั้งหมดของคลาสหรืออินเทอร์เฟซเดียวกัน ... ซึ่งเป็นจุดเชื่อมต่อและคลาสย่อย
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.