อะไรคือความแตกต่างระหว่างประเภทตนเองและการสืบทอดลักษณะในสกาลา?


9

เมื่อ Googled มีคำตอบมากมายสำหรับหัวข้อนี้ อย่างไรก็ตามฉันไม่รู้สึกว่าพวกเขาทำงานได้ดีในการอธิบายความแตกต่างระหว่างคุณสมบัติทั้งสองนี้ ดังนั้นฉันอยากลองอีกครั้งโดยเฉพาะ ...

อะไรคือสิ่งที่สามารถทำได้กับประเภทตนเองและไม่ได้มีมรดกและในทางกลับกัน?

สำหรับฉันมันควรจะมีความแตกต่างเชิงปริมาณระหว่างสองอย่างใดอย่างหนึ่ง

หากลักษณะ A ขยาย B หรือประเภทตนเอง B ทั้งคู่ไม่แสดงให้เห็นว่าการเป็น B เป็นข้อกำหนดหรือไม่ ความแตกต่างอยู่ที่ไหน


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

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

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

ตกลงคิดว่าฉันสามารถลองก่อนที่เงินรางวัลจะหมด;)
มันบรูซ

คำตอบ:


11

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

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

ความแตกต่างก็คือที่ A และ B ให้วิธีการในชื่อเดียวกัน เมื่อ A ขยาย B วิธี A จะแทนที่ B's เมื่อ A ผสมกันหลังจาก B วิธีของ A ก็ชนะ

การอ้างอิงด้วยตนเองที่พิมพ์ออกมาจะช่วยให้คุณมีอิสระมากขึ้น การมีเพศสัมพันธ์ระหว่าง A และ B นั้นหลวม

UPDATE:

เนื่องจากคุณไม่ชัดเจนเกี่ยวกับประโยชน์ของความแตกต่างเหล่านี้ ...

หากคุณใช้การสืบทอดโดยตรงคุณจะสร้างลักษณะ A ซึ่งก็คือ B + A คุณได้ตั้งค่าความสัมพันธ์ในหิน

หากคุณใช้การอ้างอิงตนเองที่พิมพ์แล้วใครก็ตามที่ต้องการใช้คุณลักษณะ A ของคุณในคลาส C สามารถทำได้

  • ผสม B แล้ว A เข้ากับ C
  • ผสมชนิดย่อยของ B แล้ว A เป็น C
  • ผสม A เป็น C โดยที่ C คือคลาสย่อยของ B

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

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

เมื่อคุณผสมในลำดับของลักษณะเมื่อใดก็ตามที่foo()มีการเรียกใช้เมธอดคอมไพเลอร์จะไปที่ลักษณะสุดท้ายที่รวมกันเพื่อค้นหาfoo()จากนั้น (หากไม่พบ) มันจะข้ามลำดับไปทางซ้ายจนกระทั่งพบลักษณะที่ใช้foo()และใช้งาน ที่. A ยังมีตัวเลือกในการโทรsuper.foo()ซึ่งจะข้ามลำดับไปทางซ้ายจนกระทั่งพบการใช้งานและอื่น ๆ

ดังนั้นถ้า A มีการอ้างอิงตัวเองพิมพ์ไปยัง B และผู้เขียนของ A รู้ว่า B ดำเนินการfoo(), A สามารถโทรsuper.foo()รู้ว่าถ้าไม่มีอะไรให้foo()B จะ อย่างไรก็ตามผู้สร้างคลาส C มีตัวเลือกเพื่อวางลักษณะอื่น ๆ ที่ใช้foo()และ A จะได้รับสิ่งนั้นแทน

อีกครั้งนี้จะมีประสิทธิภาพมากขึ้นและน้อยกว่าการ จำกัด การขยาย B โดยตรงและเรียกรุ่น B foo()ของ


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

อืมทำไมคุณต้องการให้ A ขยายคลาสย่อยของ B ถ้า B กำหนดสิ่งที่คุณต้องการ การอ้างอิงตนเองบังคับให้ B (หรือคลาสย่อย) ปรากฏ แต่ให้ตัวเลือกนักพัฒนา tbe หรือไม่ พวกเขาสามารถผสมในบางสิ่งที่พวกเขาเขียนหลังจากที่คุณเขียนคุณลักษณะ A ตราบใดที่มันขยาย B ทำไมต้อง จำกัด พวกเขาเฉพาะกับสิ่งที่มีให้เมื่อคุณเขียนลักษณะ A เท่านั้น
itsbruce

อัปเดตเพื่อสร้างความแตกต่างอย่างชัดเจน
itsbruce

@itsbruce มีความแตกต่างทางแนวคิดหรือไม่? IS-A กับ HAS-A
Jas

@Jas ในบริบทของความสัมพันธ์ระหว่างลักษณะAและB การสืบทอดคือIS-Aขณะที่การอ้างอิงตัวเองที่พิมพ์ให้HAS-A (ความสัมพันธ์แบบประพันธ์) สำหรับคลาสที่มีการผสมลักษณะผลลัพธ์จะเป็น IS-Aโดยไม่คำนึงถึง
itsbruce

0

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

trait A1 {
  self: B =>

  def doit {
    println(bar)
  }
}

trait A2 extends B {
  def doit {
    println(bar)
  }
}

trait B {
  def bar = "default bar"
}

trait BX extends B {
  override def bar = "bar bx"
}

trait BY extends B {
  override def bar = "bar by"
}

object Test extends App {
  // object Thing1 extends A1  // FAIL: does not conform to A1 self-type
  object Thing1 extends A1 with B
  object Thing2 extends A2

  object Thing1X extends A1 with BX
  object Thing1Y extends A1 with BY
  object Thing2X extends A2 with BX
  object Thing2Y extends A2 with BY

  Thing1.doit  // default bar
  Thing2.doit  // default bar
  Thing1X.doit // bar bx
  Thing1Y.doit // bar by
  Thing2X.doit // bar bx
  Thing2Y.doit // bar by

  // up-cast
  val a1: A1 = Thing1Y
  val a2: A2 = Thing2Y

  // println(a1.bar)    // FAIL: not visible
  println(a2.bar)       // bar bx
  // println(a2.bary)   // FAIL: not visible
  println(Thing2Y.bary) // 42
}

หนึ่งความแตกต่างที่สำคัญ IMO คือการที่A1ไม่เปิดเผยว่ามันเป็นความต้องการBที่จะอะไรที่แค่เห็นว่ามันเป็นA1(เช่นแสดงในชิ้นส่วนขึ้นหล่อ) รหัสเดียวที่จริงจะเห็นว่ามีการใช้ความเชี่ยวชาญเฉพาะด้านBเป็นรหัสที่รู้อย่างชัดเจนเกี่ยวกับประเภทที่ประกอบแล้ว (เช่นThink*{X,Y})

อีกจุดหนึ่งคือA2(พร้อมส่วนขยาย) จะใช้งานจริงBหากไม่มีสิ่งใดที่ระบุในขณะที่A1(ประเภทตัวเอง) ไม่ได้บอกว่ามันจะใช้Bเว้นแต่จะแทนที่ทับคอนกรีต B จะต้องได้รับอย่างชัดเจนเมื่อวัตถุถูกยกตัวอย่าง

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