चलो चक्रीय निर्भरता के साथ शुरू करते हैं।
trait A {
selfA: B =>
def fa: Int }
trait B {
selfB: A =>
def fb: String }
हालाँकि, इस समाधान की मापकता उतनी महान नहीं है जितनी पहली बार दिखाई दे सकती है, क्योंकि आप स्वयं प्रकार को ओवरराइड कर सकते हैं:
trait A1 extends A {
selfA1: B =>
override def fb = "B's String" }
trait B1 extends B {
selfB1: A =>
override def fa = "A's String" }
val myObj = new A1 with B1
यद्यपि, यदि आप किसी स्व-प्रकार के सदस्य को ओवरराइड करते हैं, तो आप मूल सदस्य तक पहुँच खो देते हैं, जो अभी भी वंशानुक्रम का उपयोग करके सुपर के माध्यम से पहुँचा जा सकता है। तो विरासत के उपयोग से वास्तव में क्या हासिल होता है:
trait AB {
def fa: String
def fb: String }
trait A1 extends AB
{ override def fa = "A's String" }
trait B1 extends AB
{ override def fb = "B's String" }
val myObj = new A1 with B1
अब मैं केक पैटर्न की सभी बारीकियों को समझने का दावा नहीं कर सकता, लेकिन यह मुझे चौंकाता है कि प्रतिरूपता को लागू करने का मुख्य तरीका विरासत या आत्म प्रकारों के बजाय रचना के माध्यम से है।
वंशानुक्रम संस्करण छोटा है, लेकिन मुख्य कारण जो मुझे स्व प्रकारों पर विरासत पसंद है, वह यह है कि मुझे प्रारंभिक प्रकार को आत्म प्रकारों के साथ सही करने के लिए अधिक मुश्किल लगता है। हालाँकि, कुछ चीजें हैं जो आप स्वयं प्रकार के साथ कर सकते हैं जो आप विरासत के साथ नहीं कर सकते हैं। स्व प्रकार एक प्रकार का उपयोग कर सकते हैं जबकि विरासत के लिए एक विशेषता या एक वर्ग की आवश्यकता होती है:
trait Outer
{ type T1 }
trait S1
{ selfS1: Outer#T1 => } //Not possible with inheritance.
आप भी कर सकते हैं:
trait TypeBuster
{ this: Int with String => }
हालाँकि आप इसे कभी भी इंस्टाल नहीं कर पाएंगे। मुझे किसी भी प्रकार से विरासत में नहीं मिलने का कोई पूर्ण कारण दिखाई नहीं देता है, लेकिन मुझे निश्चित रूप से लगता है कि पथ निर्माता वर्ग और लक्षण होना उपयोगी होगा क्योंकि हमारे पास टाइप निर्माता / वर्ग हैं। दुर्भाग्य से
trait InnerA extends Outer#Inner //Doesn't compile
हमारे पास यह है:
trait Outer
{ trait Inner }
trait OuterA extends Outer
{ trait InnerA extends Inner }
trait OuterB extends Outer
{ trait InnerB extends Inner }
trait OuterFinal extends OuterA with OuterB
{ val myV = new InnerA with InnerB }
या यह:
trait Outer
{ trait Inner }
trait InnerA
{this: Outer#Inner =>}
trait InnerB
{this: Outer#Inner =>}
trait OuterFinal extends Outer
{ val myVal = new InnerA with InnerB with Inner }
एक बिंदु जिसे सहानुभूति अधिक होनी चाहिए वह यह है कि लक्षण कक्षाओं का विस्तार कर सकते हैं। इस ओर इशारा करने के लिए डेविड मैकलेवर को धन्यवाद। यहाँ मेरे अपने कोड से एक उदाहरण है:
class ScnBase extends Frame
abstract class ScnVista[GT <: GeomBase[_ <: TypesD]](geomRI: GT) extends ScnBase with DescripHolder[GT] )
{ val geomR = geomRI }
trait EditScn[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]
trait ScnVistaCyl[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]
ScnBase
स्विंग फ्रेम वर्ग से विरासत में मिला है , इसलिए इसे एक स्व प्रकार के रूप में इस्तेमाल किया जा सकता है और फिर अंत में (तात्कालिकता पर) मिलाया जा सकता है। हालाँकि, val geomR
इनहेरिट करने वाले लक्षणों का उपयोग करने से पहले इसे आरंभ करने की आवश्यकता है। इसलिए हमें पहले के प्रारंभिककरण को लागू करने के लिए एक वर्ग की आवश्यकता है geomR
। तब वर्ग ScnVista
को कई ऑर्थोगोनल लक्षणों से विरासत में लिया जा सकता है जो खुद से विरासत में मिले हैं। कई प्रकार के मापदंडों (जेनेरिक) का उपयोग करना, मॉड्यूलरिटी का एक वैकल्पिक रूप प्रदान करता है।