การออกแบบสำหรับการสืบทอดสามารถทำให้มีค่าใช้จ่ายเพิ่มเติมได้อย่างไร [ปิด]


12

ดังนั้นฉันต้องการสืบทอดจากsealed classในcsharpและถูกไฟไหม้ ไม่มีทางที่จะเปิดผนึกจนกว่าคุณจะเข้าถึงแหล่งข้อมูลได้

ฉันคิดว่า "ทำไมsealedถึงมีอยู่จริง" 4 เดือนที่แล้ว ฉันไม่สามารถเข้าใจได้แม้จะอ่านสิ่งต่าง ๆ มากมายเช่น:

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

ในที่สุดหลังจากการไตร่ตรองมากมายฉันตัดสินใจที่จะแก้ไขคำถามเดิมอย่างหนักตามชื่อเรื่องใหม่

คำถามเดิมกว้างเกินไปและอัตนัย มันเป็นพื้นถาม:

  1. ในชื่อเก่า: เหตุผลหนึ่งที่ดีในการใช้ตราประทับ
  2. ในร่างกาย: วิธีการปรับเปลี่ยนคลาสที่ปิดผนึกอย่างถูกต้อง? ลืมเกี่ยวกับมรดก ใช้องค์ประกอบ?

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

ฉันเดาว่าคำถามของฉันที่นี่คือ (และอันที่จริงแล้วเป็นไปอย่างแน่นอน) อย่างที่Mr.Mindor แนะนำฉันในการแชท : การออกแบบเพื่อการสืบทอดสามารถทำให้มีค่าใช้จ่ายเพิ่มเติมได้อย่างไร


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

11
ดูทำไมปิดผนึกกรอบการเรียนจำนวนมากอยู่ทำไม โดย Eric Lippert เขาให้เหตุผลที่ดีหลายประการในการปิดคลาส
Robert Harvey

9
จากนั้นคุณไม่ได้อ่านบทความ ย้อนกลับไปและอ่านมันอีกครั้ง. มันลดลงมาถึงสิ่งนี้: คุณไม่สามารถทำนายได้ว่าลูกค้าจะทำลายชั้นเรียนของคุณได้อย่างไรโดยขยายออกไป คุณสามารถตำหนิลูกค้าของคุณได้ แต่คุณเป็นคนที่จะต้องสนับสนุนพวกเขา
Robert Harvey

4
@Cawas เขาทำได้หรือคุณสามารถอ่านบทความที่เขาเชื่อมโยงซึ่งอธิบายรายละเอียดได้ เขาเป็นเพียงการสรุปบทความด้วยความคิดเห็นของเขา
Servy

7
ขออภัยฉันไม่ใช่คนที่คุยโวที่นี่ คำตอบสำหรับคำถามของคุณนั้นง่ายมาก: ประทับตราชั้นเรียนเมื่อคุณไม่ต้องการสนับสนุนการสืบทอด แค่นั้นแหละ.
Robert Harvey

คำตอบ:


27

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

คนส่วนใหญ่บ่นเกี่ยวกับการไม่สามารถขยายชั้นเรียนและถ้าพวกเขาทำแล้วพวกเขาบอกว่าดีทุกคนรู้ว่ามันเป็นความรับผิดชอบของนักพัฒนาเพื่อให้ทำงานได้อย่างถูกต้อง ถูกต้องยกเว้นคนเดียวกันนั้นไม่มีเงื่อนงำเกี่ยวกับประวัติของ Windows และหนึ่งในปัญหาsealedกำลังพยายามแก้ไข

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

ตอนนี้ Microsoft เปิดตัวระบบปฏิบัติการใหม่ซึ่งรวมถึงการแก้ไขข้อบกพร่องในระดับแกนหลัก. Net นี้โดยเฉพาะ ลูกค้าต้องการติดตามเวลาและเลือกที่จะติดตั้งระบบปฏิบัติการใหม่ ในทันทีที่แอปพลิเคชันที่ลูกค้าชื่นชอบใช้งานไม่ได้อีกต่อไปเพราะมันไม่ได้คำนึงถึงข้อผิดพลาดที่ได้รับการแก้ไขในระดับแกนกลาง. Net

ใครจะเป็นผู้ตำหนิ?

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

การใช้sealedไม่ได้เป็นการกำจัดภาพจำลองทั้งหมดอย่างสมบูรณ์ แต่สามารถช่วยได้


4
@Cawas มันค่อนข้างยากที่จะใช้มันในทางที่ผิด Eric Lippert ได้กล่าวถึงหลายครั้งที่เขาต้องการให้คลาสเช่นเดียวกับวิธีการทั้งหมดเป็นsealedค่าเริ่มต้นเว้นแต่จะถูกเปิดเผยโดยเฉพาะเพราะชั้นเรียนเพียงไม่กี่แห่งที่ได้รับการออกแบบมาเพื่อสืบทอด มีโอกาสมากขึ้นที่ชั้นเรียนของคุณไม่ได้ถูกสร้างขึ้นเพื่อสนับสนุนและคุณควรตรวจสอบให้แน่ใจว่าคุณใช้เวลาในการพัฒนานั้นถ้าคุณออกนอกเส้นทางของคุณเพื่อทำเครื่องหมายว่าไม่ได้เปิดผนึก
Servy

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

2
@Cawas กว้างใหญ่ส่วนใหญ่ของการเรียนที่เขียนโดยนักพัฒนาส่วนใหญ่จะไม่ต้องมีการสืบทอดและไม่ได้เขียนขึ้นเพื่อสนับสนุนการถ่ายทอดทางพันธุกรรม นี้ได้อย่างรวดเร็วและมีประสิทธิภาพจะถ่ายทอดให้กับผู้อ่าน / sealedผู้ใช้รหัสโดยการพิมพ์ หากในความเป็นจริงแล้วตัวเลือกเริ่มต้นก็หมายความว่าถ้ามีคนสืบทอดจากประเภทนั้นพวกเขาจะรู้ว่ามันสร้างขึ้นเพื่อรองรับ
Servy

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

1
ความปลอดภัยยังเป็นเหตุผลที่จะใช้มัน! พิจารณาแอปพลิเคชันแบบ sandbox ที่พยายามเข้าถึงไฟล์ แซนด์บ็อกซ์อาจทดสอบชื่อไฟล์ - สตริง แต่จะเกิดอะไรขึ้นถ้าผู้โจมตีสามารถส่งข้อมูลไม่แน่นอน ให้คุณStringแล้วพวกเขาก็จะทำการเปลี่ยนแปลงหลังจากการตรวจสอบความปลอดภัย แต่ก่อน I / O? ฉันเชื่อว่าประเภทของสถานการณ์เป็นเหตุผลว่าทำไมจาวาStringถูกทำเครื่องหมายfinal(คล้ายกับsealed) และฉันเดิมพันด้วยเหตุผลเดียวกันกับการตัดสินใจของ C #
Darien

23

sealedใช้เพื่อระบุว่าผู้เขียนของคลาสไม่ได้ออกแบบมาให้สืบทอด ไม่มีอะไรน้อยไม่มีอะไรเพิ่มเติม

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

ลองจินตนาการถึงกรณีที่ชั้นมาจากCustomBoeing787 Airlinerสิ่งนี้CustomBoeing787จะแทนที่วิธีการป้องกันบางอย่างจากAirlinerแต่ไม่ใช่ทั้งหมด หากนักพัฒนามีเวลาเพียงพอและคุ้มค่าเขาสามารถทดสอบหน่วยเพื่อให้แน่ใจว่าทุกอย่างทำงานได้ตามที่คาดไว้แม้ในบริบทที่มีการเรียกวิธีที่ไม่ overriden (ตัวอย่างเช่น setters ที่มีการป้องกันซึ่งเปลี่ยนสถานะของวัตถุ) หากผู้พัฒนารายเดียวกัน (1) ไม่มีเวลา (2) ไม่ต้องการใช้เจ้านายหรือลูกค้าเพิ่มเติมหลายร้อยหรือหลายพันดอลลาร์หรือ (3) ไม่ต้องการเขียนรหัสเพิ่มเติมเขาไม่ ต้องการตอนนี้ (YAGNI) จากนั้นเขาสามารถ:

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

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

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


เอาล่ะ ... ขอโทษด้วยถ้าข้าฟังเสียงก้าวร้าวอีกครั้ง แต่ข้าต้องการที่จะชัดเจนและแน่วแน่ที่นี่ ... ข้าสามารถเข้าใจสิ่งที่ท่านเขียนในสองวิธีนี้ถ้าท่านจะเขียนtl;drที่นี่ มันอาจเป็น"ไม่ไม่มีเหตุผลที่ดีเพียงอย่างเดียว"หรือ"ฉันคิดว่าไม่มีเหตุผลที่ดี แต่ฉันก็ไม่รู้เหมือนกัน" . สำหรับฉัน "ไม่มีคำตอบที่ชัดเจน" เป็นหนึ่งในนั้น
cregox

6
sealedใช้เพื่อระบุว่าผู้เขียนของคลาสไม่ได้ออกแบบมาให้สืบทอด นั่นคือเหตุผลเดียวที่ดีของคุณ
Robert Harvey

นั่นเป็นเหตุผลที่ดีที่ให้จักรยานที่ไม่มีไฟและการบังคับใช้แก่คุณคุณไม่สามารถเพิ่มไฟได้
cregox

2
@Cawas เป็นไงบ้าง? ในบริบทนั้นมันไม่สำคัญสำหรับผู้สร้างจักรยานเพื่อให้แน่ใจว่าจักรยานไม่ได้มีน้ำหนักเบา แต่มักจะเป็นสิ่งสำคัญสำหรับผู้ใช้งานประเภทหนึ่งเพื่อให้แน่ใจว่า คุณบังคับใช้ข้อ จำกัด ที่คุณต้องการ ในบางกรณีผู้คนอาจเพิ่มข้อ จำกัด ที่ไม่จำเป็นต้องใช้จริง คุณได้ให้ตัวอย่างของสิ่งนั้น เพียงเพราะข้อ จำกัด นั้นถูกใช้อย่างผิด ๆ ในที่เดียวไม่ได้หมายความว่าคุณไม่ควร จำกัด อะไรเลย
Servy

1
ความปลอดภัยยังเป็นเหตุผลที่จะใช้มัน! พิจารณาแอปพลิเคชันแบบ sandbox ที่พยายามเข้าถึงไฟล์ แซนด์บ็อกซ์อาจทดสอบชื่อไฟล์ - สตริง แต่จะเกิดอะไรขึ้นถ้าผู้โจมตีสามารถส่งข้อมูลไม่แน่นอน ให้คุณStringแล้วพวกเขาก็จะทำการเปลี่ยนแปลงหลังจากการตรวจสอบความปลอดภัย แต่ก่อน I / O? ฉันเชื่อว่าประเภทของสถานการณ์เป็นเหตุผลว่าทำไมจาวาStringถูกทำเครื่องหมายfinal(คล้ายกับsealed) และฉันเดิมพันด้วยเหตุผลเดียวกันกับการตัดสินใจของ C #
Darien

4

เมื่อชั้นเรียนถูกปิดผนึกจะช่วยให้รหัสที่ใช้ประเภทนั้นรู้ว่าพวกเขากำลังทำอะไรอยู่

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

public class EvilString// : String
{
    public override string ToString()
    {
        throw new Exception("I'm mean");
    }
    public override bool Equals(object obj)
    {
        return false;
    }
    public override int GetHashCode()
    {
        return 0;
    }
}

นี่จะเป็นคลาสสตริงที่ละเมิดคุณสมบัติทุกประเภทที่ผู้ออกแบบstringรู้ว่าเป็นจริง พวกเขารู้ว่าEqualsวิธีนี้จะเป็นสกรรมกริยานี่ไม่ใช่ Heck วิธีนี้เท่ากับไม่สมมาตรเนื่องจากสตริงอาจเท่ากับมัน แต่มันจะไม่เท่ากับสตริงนั้น ฉันแน่ใจว่ามีโปรแกรมเมอร์ทุกประเภทที่เขียนโค้ดภายใต้สมมติฐานว่าToStringวิธีการstringจะไม่ส่งข้อยกเว้นสำหรับค่าที่ไม่ใช่ค่าว่าง ตอนนี้คุณจะสามารถละเมิดสมมติฐานนี้ได้

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


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

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

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

2
@Cawas stringประเภทไม่ได้เป็นรหัสคอมไพเลอร์ มันเป็นส่วนหนึ่งของรหัสภาษา แตกต่างอย่างสิ้นเชิง ฉันเลือกตัวอย่างหนึ่งตัวอย่าง คุณสามารถเลือกคลาสที่ปิดผนึกได้เกือบทั้งหมดใน BCL ทั้งหมดและใช้เป็นตัวอย่าง
Servy

4
@Cawas: ฉันคิดว่าสิ่งที่คุณอาจขาดหายไปที่นี่คือด้านการสนับสนุนลูกค้า หากคุณอนุญาตให้ชั้นเรียนสามารถสืบทอดได้ลูกค้าจะได้รับมรดกจากชั้นเรียนแล้วพวกเขาจะโทรหาคุณเมื่อถึงเวลาพัก คุณสามารถบอกพวกเขาได้ตลอดทั้งวันว่าพวกเขาได้รับมรดกจากชั้นเรียนนั้นด้วยความเสี่ยงของตัวเองแต่คุณยังคงต้องรับสายเพราะคุณอนุญาตให้พวกเขาสืบทอดสายนั้นได้ดังนั้นพวกเขาจึงคิดว่าปลอดภัย
Robert Harvey

3

มีเหตุผลที่ดีที่จะใช้ผนึกหรือไม่?

Enh? ไม่บ่อย. ฉันจะใช้การปิดผนึกเฉพาะเมื่อฉันมีรูปแบบที่ไม่เปลี่ยนรูปแบบ (หรือข้อ จำกัด อื่น ๆ ) ที่จำเป็นต้องทำให้ไม่สามารถเปลี่ยนแปลงได้จริง และฉันไม่สามารถไว้วางใจผู้สืบทอดที่จะทำให้ข้อกำหนดเหล่านั้นแย่ลงโดยไม่แนะนำแมลงที่รุนแรง

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

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

ฉันไม่ได้ตั้งใจว่าจะเกินไปแต่ถ้าตอนนี้คุณเพิ่งได้ยินเรื่อง SOLID และการทดสอบหน่วยบางทีคุณควรจะออกไปจากหินและเขียนโค้ด สิ่งต่าง ๆ ไม่ชัดเจนและไม่ค่อย "ทำ X" หรือ "ไม่เคยใช้ Y" หรือ "Z ดีที่สุด" มักจะเป็นวิธีที่ถูกต้อง เมื่อคุณเขียนโค้ดคุณจะเห็นกรณีที่sealedอาจดีและกรณีที่ทำให้คุณเสียใจ - เช่นเดียวกับการแลกเปลี่ยนอื่น ๆ


ให้ฉันนี้และ "เพื่อหลีกเลี่ยงการสนับสนุนมรดกให้กับลูกค้า" ที่โรเบิร์ตไม่ต้องการที่จะทำอย่างละเอียดเป็นคำตอบที่มีแนวโน้มมากที่สุด ... บางทีคุณอาจจะอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับกรณีที่คุณทำใช้sealedหน่อยได้ไหม?
cregox

@Cawas - ฉันไม่แน่ใจว่าฉันทำได้ดี ฉันไม่ค่อยทำมันและมันมักจะเป็นการแลกเปลี่ยนที่รับประกันว่าสิ่งที่ไม่เปลี่ยนแปลง (เพื่อเพิ่มประสิทธิภาพประสิทธิภาพการออกแบบที่เรียบง่าย) มีค่าไม่สามารถที่จะสืบทอดจากวัตถุ
Telastyn

มันเท่ห์มาก Dunk แล้ว dunked มัน! : P ขอบคุณมากสำหรับคำตอบ และคุณเป็นคนเดียวในการรับ "คำแนะนำที่ละเอียดอ่อน" ของฉันเกี่ยวกับความเชี่ยวชาญของฉัน ดูเหมือนว่าผู้คนกำลังสมมติว่าฉันรู้มากขึ้นฉันไม่รู้ ... แต่ฉันหวังว่า "แค่โค้ด" จะพาฉันออกไปจากหินก้อนนี้ บางทีฉันอาจนำแนวคิดเหล่านั้นไปใช้ในทางใดทางหนึ่งไม่ได้เป็นขั้นตอนตามที่ควรจะเป็น
cregox

3

ก่อนอื่นคุณควรอ่านโพสต์ของ Eric Lippert ว่าทำไม Microsoft ถึงผนึกคลาสไว้

http://blogs.msdn.com/b/ericlippert/archive/2004/01/22/61803.aspx

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

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


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

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

ขึ้นอยู่กับว่าคุณควบคุม codebase หรือไม่ หากคุณปิดคลาสคุณสามารถปิดผนึกได้ในภายหลังหากจำเป็น
Stephen

2

ฉันคิดว่าคำถามนี้ไม่มีคำตอบที่ตรงประเด็นและทุกอย่างขึ้นอยู่กับมุมมองของคุณ

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

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


มันเป็นมากกว่านี้! นี่อาจเป็นเหตุผลที่ดี ... "เพราะคนต้องการปิด" และมันก็เป็นสิ่งที่ฉันพยายามจะพูดในคำถาม: ดูเหมือนว่าชั้นเรียนที่ไม่ใช่เสมือนจริงใน C ++ สามารถถูกแทนที่ได้ sealedลาด. เราจะสืบทอดจากพวกเขาได้อย่างไร สิ่งที่ฉันอ่านคือเราทำไม่ได้ เคย ฉันไม่รู้ ฉันกลับมาเรื่องนี้มา 4 เดือนแล้วตั้งแต่ครั้งแรกที่ฉันได้ยินเรื่องผนึก และฉันก็ยังไม่รู้ว่าจะทำอย่างไรเมื่อต้องแก้ไขอะไรในชั้นเรียนที่ปิดผนึก ดังนั้นฉันไม่เห็น "ตัวเลือกเพื่อเปิด"!
cregox

4
นี่ไม่ใช่เหตุผลที่คลาส C ++ ไม่เสมือนโดยค่าเริ่มต้น การสร้างเมธอดเสมือนหมายถึงจะต้องมีค่าใช้จ่ายเพิ่มเติมในตารางการค้นหาเมธอดและ C ++ มีปรัชญาที่คุณจ่ายเฉพาะค่าใช้จ่ายเมื่อคุณต้องการคุณลักษณะ
Michael Shaw

@Poleole Ok ฉันลบออกแล้ว ฉันไม่ควรเขียนเพราะฉันรู้ว่าผู้คนเริ่มบ่นเกี่ยวกับมัน
สุข

เฮ้ฉันขอขอบคุณอย่างสมบูรณ์ว่าถ้าคุณต้องการอ้างว่าคนต้องการเขียนคลาสปิดโดยค่าเริ่มต้นและต้องเลือกที่จะเปิดพวกเขาอย่างแข็งขันแล้วคุณจะต้องจับฟาง
Michael Shaw

IMO มันคล้ายกับการอภิปรายส่วนตัว / ที่มีการป้องกัน / สาธารณะเมื่อพูดถึง API: มันขึ้นอยู่กับว่าใครควบคุมคลาสใครต้องการสืบทอดคลาสการสื่อสารระหว่างคนทั้งสองและรุ่นใหม่ ๆ ออกมาบ่อยแค่ไหน
Darien

-2

ปัญหาเกี่ยวกับการปิดผนึกใน C # นั้นค่อนข้างสุดท้าย ใน 7 ปีของการพัฒนาเชิงพาณิชย์ C # ที่เดียวที่ฉันเคยเห็นคือใช้ในคลาส Microsoft .NET ซึ่งฉันรู้สึกว่าฉันมีเหตุผลที่ถูกต้องตามกฎหมายที่จะขยายคลาสเฟรมเวิร์กเพื่อใช้พฤติกรรมที่ปรับแล้วและเนื่องจากคลาสถูกปิดผนึก .

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

ดังนั้นโดยสรุปฉันมั่นใจในมุมมองที่ปิดผนึกไม่ได้มีประโยชน์และไม่มีอะไรที่ฉันได้อ่านที่นี่จนถึงตอนนี้ได้เปลี่ยนมุมมองนั้น

ฉันสามารถเห็นได้ว่ามีสามข้อโต้แย้งที่แสดงให้เห็นถึงการปิดผนึกที่วางไว้จนถึงขณะนี้

  1. ข้อโต้แย้งที่ 1 คือมันกำจัดแหล่งที่มาของข้อบกพร่องเมื่อผู้คนได้รับมรดกจากชั้นเรียนและจากนั้นได้เพิ่มการเข้าถึง internals ของชั้นเรียนนั้นโดยไม่ต้องเข้าใจภายในอย่างถูกต้อง

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

  3. อาร์กิวเมนต์ 3 คือในฐานะผู้พัฒนาคลาสฉันเลือกได้ว่าจะให้คุณขยายมันเป็นส่วนหนึ่งของการออกแบบคลาสของฉันหรือไม่

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

ฉันเข้าใจว่าฐานข้อเท็จจริงสำหรับ arg 2 มาจากไหน โดยเฉพาะอย่างยิ่งเมื่อไมโครซอฟท์ทำการตรวจสอบระบบปฏิบัติการเพิ่มเติมเกี่ยวกับการเรียก win32 api เพื่อระบุการโทรที่มีรูปแบบไม่ถูกต้องซึ่งได้ปรับปรุงเสถียรภาพทั่วไปของ Windows XP เมื่อเทียบกับ Windows NT แต่ในระยะเวลาสั้น ๆ Microsoft แก้ไขปัญหานี้โดยการใส่ 'กฎ' เพื่อให้การตรวจสอบเหล่านี้พูดไม่สนใจเมื่อแอป X ละเมิดกฎนี้ซึ่งเป็นข้อบกพร่องที่รู้จัก

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

อาร์กิวเมนต์ 3 เป็นอาร์กิวเมนต์เดียวที่มีเนื้อหาใด ๆ ที่จะปรับตัวเอง แต่มันก็ยังอ่อนแอ มันขัดกับธัญพืชที่นำมาใช้ใหม่


2
/ ฉันส่งอีเมลไปยัง microsoft โปรดช่วยคุณเปิด class X สำหรับฉันและส่งออก. NET รุ่นใหม่ ขอแสดงความนับถือ, .... อย่างที่ฉันบอก, ครั้งเดียวในการพัฒนาเชิงพาณิชย์ที่ฉันได้เห็นชั้นเรียนที่ปิดสนิท, มันเป็นไปไม่ได้ที่จะเปิดเผยมัน
Michael Shaw

6
It is impossible to write a class thinking about every possible way it could be used- นั่นคือเหตุผลที่ปิดคลาสของกรอบงานหลายอย่าง ... มันไม่จำเป็นต้องคิดเกี่ยวกับวิธีที่เป็นไปได้ที่ใครบางคนอาจขยายชั้นเรียน
Robert Harvey

5
หากคุณสามารถเปิดผนึกได้มันจะไม่มีประเด็นมากในการผนึกมัน
Robert Harvey

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

2
@Cawas: คุณแค่เป็นเรื่องยาก
Robert Harvey


-8

เห็นได้ชัดจากคำถามของฉันฉันไม่มีผู้เชี่ยวชาญที่นี่ แต่ฉันไม่เห็นเหตุผลที่sealedจะมีอยู่

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

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

อาจมีคำหลักstableดังนั้นผู้คนจะรู้ว่าปลอดภัยกว่าที่จะรับมรดกจากมัน


2
"แก้ไขปัญหา" - อย่างแน่นอน
Robert Harvey

@RobertHarvey ไม่ได้รับการแก้ไขตามที่อธิบายไว้ในย่อหน้าถัดไป
cregox

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

ฉันไม่เคยบอกว่ามันไม่มีประโยชน์ ฉันว่าฉันไม่เห็นการใช้งานและชี้ให้เห็นว่าทำไม ได้โปรดฉันขอร้องคุณให้ฉันใช้เหตุผลที่ดี! แม้ว่ามันจะเป็นเพียง "เพราะฉันต้องการทำตามรูปแบบการออกแบบที่ปิด" แต่ก็ไม่เป็นไร ฉันไม่เห็นใครให้เหตุผลนั้นอย่างชัดเจน
cregox

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