คุณจะปิดชั้นเรียนเมื่อใดและทำไม


89

ใน C # และ C ++ / CLI คีย์เวิร์ดsealed(หรือNotInheritableใน VB) ถูกใช้เพื่อป้องกันคลาสจากโอกาสในการสืบทอด (คลาสจะไม่สามารถสืบทอดได้) ฉันรู้ว่าคุณลักษณะหนึ่งของการเขียนโปรแกรมเชิงวัตถุคือการสืบทอดและฉันรู้สึกว่าการใช้งานsealedขัดกับคุณลักษณะนี้จะหยุดการสืบทอด มีตัวอย่างที่แสดงให้เห็นถึงประโยชน์ของการใช้sealedและเวลาที่สำคัญหรือไม่?

คำตอบ:


100
  1. ในคลาสที่ใช้คุณลักษณะด้านความปลอดภัยเพื่อไม่ให้อ็อบเจ็กต์ดั้งเดิมถูก "เลียนแบบ"

  2. โดยทั่วไปเมื่อเร็ว ๆ นี้ฉันได้แลกเปลี่ยนกับบุคคลที่ Microsoft ซึ่งบอกฉันว่าพวกเขาพยายาม จำกัด การสืบทอดให้อยู่ในสถานที่ที่เหมาะสมจริงๆเพราะมันจะกลายเป็นประสิทธิภาพที่มีราคาแพงหากไม่ได้รับการรักษา
    คีย์เวิร์ดที่ปิดผนึกจะบอก CLR ว่าไม่มีคลาสใดเพิ่มเติมในการค้นหาวิธีการและทำให้สิ่งต่างๆเร็วขึ้น

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


3
ฉันตั้งใจจะระวังการปิดผนึกคลาสในไลบรารีที่ใช้ซ้ำโดยเฉพาะอย่างยิ่งหากบุคคลที่สามถูกนำกลับมาใช้ซ้ำแล้วรวมเข้าใหม่ (ผ่าน MEF) ในโค้ดเบส โค้ดเบสของคุณอาจไม่สืบทอดคลาสที่กำหนด แต่บุคคลที่สามจะรับ
Louis Kottmann

10
เหตุผล # 1 ฟังดูคลุมเครือ แต่สมมติว่าเราไม่ได้เขียน "คุณลักษณะด้านความปลอดภัย" เกือบตลอดเวลานั่นหมายความว่าเหตุผล # 1 แทบจะไม่ได้ใช้หรือไม่? เหตุผล # 2 มีไว้สำหรับการปรับแต่งประสิทธิภาพ เรากำลังพูดถึงความแตกต่างของประสิทธิภาพมากแค่ไหน? มีความสำคัญเพียงพอที่จะปรับเปลี่ยนนิยามของคลาสที่ไม่ใช่ความปลอดภัยหรือไม่ แม้ว่าคำตอบจะเป็น "ใช่" แต่ก็ควรเป็นตัวเลือกคอมไพเลอร์เช่น "สร้างโค้ดที่ปรับให้เหมาะสมสำหรับคลาสที่ไม่ปิดผนึกทั้งหมด" แทนที่จะให้เรานักพัฒนาแก้ไขฐานโค้ด
RayLuo

1
มันจะกลายเป็นประสิทธิภาพที่มีราคาแพงหากปล่อยทิ้งไว้โดยไม่ได้รับการรักษาสิ่งนี้สามารถวัดได้ด้วยการทดสอบที่บ้าคลั่งน้อยลงหรือไม่?
t3chb0t

4
การปิดผนึกห่วย ทำให้การทดสอบยากขึ้น - ฉันอยากจะล้อเลียนคลาส ASP.NET สองสามคลาสกับ FakeItEasy แต่ฉันทำไม่ได้เพราะมันถูกปิดผนึก
Warlike Chimpanzee

2
ไม่เห็นด้วยกับ @RayLuo หลายครั้งที่ผู้คนปิดผนึกชั้นเรียนโดยที่ความปลอดภัยและประสิทธิภาพไม่ใช่ปัญหาจริงๆ การ "ปิดผนึก" ของพวกเขาเพียงแค่ขัดขวางความต้องการที่สมเหตุสมผลของฉันในการเอาชนะชั้นเรียนทำให้สิ่งต่างๆยากขึ้น เช่นเดียวกับ Warlike Chimpanzee กล่าวว่าการล้อเลียนชั้นเรียนเป็นเรื่องปกติในการทดสอบ
ZZY

15

ภาคผนวกสำหรับคำตอบที่ยอดเยี่ยมของ Baboon :

  1. หากคลาสไม่ได้ออกแบบมาสำหรับการสืบทอดคลาสย่อยอาจทำลายค่าคงที่ของคลาสได้ สิ่งนี้ใช้ได้เฉพาะในกรณีที่คุณกำลังสร้าง API สาธารณะเท่านั้น แต่ตามหลักทั่วไปฉันปิดผนึกคลาสใด ๆ ที่ไม่ได้ออกแบบอย่างชัดเจนให้เป็นคลาสย่อย

ในบันทึกที่เกี่ยวข้องใช้ได้กับคลาสที่ไม่ได้ปิดผนึกเท่านั้น: วิธีการใด ๆ ที่สร้างขึ้นvirtualเป็นจุดขยายหรืออย่างน้อยก็ดูเหมือนว่าควรเป็นจุดขยาย วิธีการประกาศvirtualควรเป็นการตัดสินใจอย่างมีสติเช่นกัน (ใน C # นี่เป็นการตัดสินใจอย่างมีสติใน Java ไม่ใช่)


แก้ไข : ลิงค์ที่เกี่ยวข้องบางส่วน:

โปรดทราบว่าKotlinผนึกคลาสโดยค่าเริ่มต้น มันopenเป็นหลักตรงข้ามของ Java ของfinalหรือsealedของ C # (เพื่อให้แน่ใจว่าไม่มีข้อตกลงสากลว่านี่เป็นสิ่งที่ดี )


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

9
ความคิดเห็นของ @GantMan ควรได้รับการพิจารณาว่าเป็นหนึ่งในคำตอบสำหรับคำถามของ OP เพราะโดยพื้นฐานแล้วจะให้คำตอบว่า "When? Hardly. Why? นี่คือเหตุผลว่าทำไมคุณถึงไม่ทำเช่นนั้น" ให้สิทธิ์คุณควรโพสต์ความคิดเห็นของคุณอีกครั้งเป็นคำตอบแยกต่างหากจากนั้นรวบรวมคะแนนสำหรับความคิดเห็นนั้น :-)
RayLuo

1
นี่เป็นการแสดงความคิดเห็นต่อคำตอบนี้ หรือไม่: stackoverflow.com/a/7777674/3195477 ? ดีกว่าที่จะเชื่อมโยงไปยังชื่อบุคคล (เท่านั้น)
UuDdLrLrSs

2

การทำเครื่องหมายคลาสเป็นการSealedป้องกันการปลอมแปลงคลาสสำคัญที่อาจทำให้ความปลอดภัยลดลงหรือส่งผลต่อประสิทธิภาพ

หลายครั้งการปิดผนึกคลาสก็สมเหตุสมผลเช่นกันเมื่อมีการออกแบบคลาสยูทิลิตี้ที่มีพฤติกรรมคงที่ซึ่งเราไม่ต้องการเปลี่ยนแปลง

ตัวอย่างเช่นSystemเนมสเปซในC#มีหลายคลาสที่ปิดผนึกเช่นString. หากไม่ได้ปิดผนึกอาจเป็นไปได้ที่จะขยายฟังก์ชันการทำงานซึ่งอาจไม่เป็นที่ต้องการเนื่องจากเป็นประเภทพื้นฐานที่มีฟังก์ชันการทำงานที่กำหนด

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

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

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


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

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

ลองดูโพสต์ที่ยอดเยี่ยมนี้จาก Eric Lippert และคำถาม SOนี้
Akshay Khot

1
แม้คำตอบนั้นโดยพื้นฐานแล้วจะกลายเป็น "ทำไมคุณถึงต้องการได้รับ String?" จากนั้นก็กล่าวถึงเหตุผลที่คุณอาจต้องการได้รับ String (เช่นสตริงที่สิ้นสุดด้วยค่าว่าง) และบอกว่าคุณควรแก้ไขโดยไม่ให้สืบทอด เหตุใดจึงทำให้ซับซ้อนมากขึ้นและต้องแก้ไขในภายหลังเมื่อคุณสามารถปล่อยให้เปิดผนึกไว้ตั้งแต่แรกและปล่อยให้ตัวเลือกของคุณเปิดอยู่
Kevin Wells

สำหรับคำถามที่สองเป้าหมายคือเพื่อป้องกันพฤติกรรมที่ไม่ต้องการ (ขึ้นอยู่กับตรรกะทางธุรกิจ) มันง่ายกว่าสำหรับunsealคลาสในภายหลังหากจำเป็นแทนที่จะปิดผนึกและทำลายคลาสทั้งหมดที่ขึ้นอยู่กับคลาสนั้น
Akshay Khot

0

ฉันคิดว่าโพสต์นี้มีจุดที่ดีกรณีเฉพาะคือเมื่อพยายามส่งคลาสที่ไม่ปิดผนึกไปยังอินเทอร์เฟซแบบสุ่มใด ๆ คอมไพเลอร์จะไม่แสดงข้อผิดพลาด แต่เมื่อใช้การปิดผนึกคอมไพเลอร์จะแสดงข้อผิดพลาดที่ไม่สามารถแปลงได้ คลาสปิดผนึกเพิ่มความปลอดภัยในการเข้าถึงรหัส
https://www.codeproject.com/Articles/239939/Csharp-Tweaks-Why-to-use-the-sealed-keyword-on-cla


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

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

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