คลาสควรรู้เกี่ยวกับคลาสย่อยหรือไม่? คลาสควรทำสิ่งที่เฉพาะเจาะจงสำหรับคลาสย่อยที่กำหนดเช่น?
สัญชาตญาณของฉันบอกฉันว่ามันเป็นการออกแบบที่ไม่ดีดูเหมือนว่าจะมีรูปแบบต่อต้านบางอย่าง
คลาสควรรู้เกี่ยวกับคลาสย่อยหรือไม่? คลาสควรทำสิ่งที่เฉพาะเจาะจงสำหรับคลาสย่อยที่กำหนดเช่น?
สัญชาตญาณของฉันบอกฉันว่ามันเป็นการออกแบบที่ไม่ดีดูเหมือนว่าจะมีรูปแบบต่อต้านบางอย่าง
คำตอบ:
คำตอบโดยนัยของแนวคิดของคลาสคือ "ไม่"
ไม่ว่าการกระทำใด ๆ ข้อมูลหรือความสัมพันธ์ที่คุณกำลังจัดการเป็นส่วนหนึ่งของคลาสย่อยทั้งหมด - ดังนั้นควรจัดการในซูเปอร์คลาสโดยไม่ตรวจสอบประเภทจริง หรือใช้กับคลาสย่อยบางคลาสเท่านั้น - จากนั้นคุณจะต้องทำการตรวจสอบชนิดรันไทม์เพื่อทำสิ่งที่ถูกต้องซุปเปอร์คลาสจะต้องเปลี่ยนเมื่อใดก็ตามที่มีคนอื่นสืบทอดจากมัน (หรืออาจทำสิ่งผิดปกติอย่างเงียบ ๆ ) การเปลี่ยนแปลงในคลาสที่ได้รับสามารถทำลายซูเปอร์คลาสที่ไม่เปลี่ยนแปลง ฯลฯ
ในระยะสั้นคุณจะได้รับผลกระทบจำนวนมากซึ่งมักจะไม่ดีพอที่จะปฏิเสธการแก้ปัญหาดังกล่าวได้ หากคลาสย่อยหลาย ๆ ตัวของคุณทำสิ่งเดียวกันและคุณต้องการหลีกเลี่ยงการทำซ้ำโค้ด (ในทางปฏิบัติเป็นสิ่งที่ดีเสมอ) ทางออกที่ดีกว่าคือการแนะนำคลาสระดับกลางซึ่งคลาสย่อยเหล่านั้นทั้งหมดสามารถสืบทอดรหัสได้
ไม่เพียง แต่ไม่ควรรู้เท่านั้นไม่สามารถทำได้ ! โดยปกติชั้นเรียนสามารถขยายได้ทุกที่ทุกเวลา มันสามารถขยายได้โดยชั้นเรียนที่ไม่ได้อยู่แม้กระทั่งเมื่อมันถูกเขียน
บางภาษาอนุญาตให้ขยายคลาสเพื่อควบคุมโดย superclass ใน Scala คลาสสามารถถูกทำเครื่องหมายเป็นsealed
ซึ่งหมายความว่าสามารถขยายได้โดยคลาสอื่นเท่านั้นภายในหน่วยการคอมไพล์เดียวกัน (ไฟล์ต้นฉบับ) อย่างไรก็ตามเว้นแต่ว่าคลาสย่อยเหล่านั้นจะเป็นเช่นนั้น sealed
หรือfinal
คลาสย่อยนั้นสามารถขยายเพิ่มเติมโดยชั้นเรียนอื่น ๆ
ใน Scala สิ่งนี้ใช้เพื่อสร้างแบบจำลองข้อมูลพีชคณิตแบบปิดดังนั้นประเภท Canonical Haskell List
:
data List a = Nil | Cons a (List a)
สามารถสร้างแบบจำลองใน Scala เช่นนี้:
sealed trait List[+A]
case object Nil extends List[Nothing]
final case class Cons[+A] extends List[A]
และคุณสามารถรับประกันได้ว่ามีเพียงคลาสย่อยสองคลาสที่มีอยู่เนื่องจากList
เป็นsealed
และไม่สามารถขยายนอกไฟล์Cons
ได้final
ดังนั้นจึงไม่สามารถขยายได้เลยและNil
เป็นสิ่งobject
ที่ไม่สามารถขยายได้
แต่นี่เป็นกรณีการใช้งานเฉพาะ (การสร้างแบบจำลองข้อมูลพีชคณิตผ่านการสืบทอด) และแม้แต่ในกรณีนี้ซูเปอร์คลาสก็ไม่ทราบเกี่ยวกับคลาสย่อยของมัน มันขึ้นรับประกันให้กับผู้ใช้ของList
ประเภทว่าถ้าเขาไม่เลือกปฏิบัติกรณีNil
และCons
จะไม่มีใด ๆอื่น ๆทางเลือกที่โผล่ขึ้นมาอยู่ข้างหลังเขา
abstract internal
สมาชิกบางรูปแบบ
คำตอบง่ายๆคือไม่
มันทำให้โค้ดเปราะและ voilates สองหลักการพื้นฐานของการเขียนโปรแกรมเชิงวัตถุ
ใช่บางเวลา. ตัวอย่างเช่นเมื่อมีคลาสย่อยจำนวน จำกัด อยู่ แขกแบบเป็นภาพของประโยชน์ของวิธีการนี้
ตัวอย่าง: โหนดต้นไม้ไวยากรณ์ (AST) ของไวยากรณ์ที่กำหนดอย่างดีบางอย่างสามารถสืบทอดมาจากNode
คลาสเดียวที่ใช้รูปแบบผู้เยี่ยมชมเพื่อจัดการกับโหนดทุกประเภท
Node
แน่นอนว่าคลาสพื้นฐานนั้นไม่มีการอ้างอิงโดยตรงไปยังคลาสย่อย แต่มันมีaccept
วิธีการที่มีVisitor
พารามิเตอร์ และVisitor
มีvisit
วิธีการต่อแต่ละคลาสย่อย ดังนั้นแม้จะNode
ไม่มีการอ้างอิงโดยตรงไปยังคลาสย่อยของมันมัน "รู้" เกี่ยวกับพวกเขาทางอ้อมผ่านVisitor
อินเตอร์เฟซ พวกเขาทั้งหมดรวมเข้าด้วยกันผ่านมัน
ถ้าฉันเขียนส่วนประกอบสำหรับ บริษัท และหลังจากนั้นหลังจากฉันออกไปมีใครบางคนขยายมันสำหรับวัตถุประสงค์ของตัวเองฉันควรทราบเกี่ยวกับเรื่องนี้หรือไม่?
No!
เช่นเดียวกันกับคลาส เชื่อสัญชาตญาณของคุณ