Döngüsel bağımlılıkla başlayalım.
trait A {
selfA: B =>
def fa: Int }
trait B {
selfB: A =>
def fb: String }
Ancak, bu çözümün modülerliği ilk göründüğü kadar büyük değildir, çünkü kendiliğinden türleri geçersiz kılabilirsiniz:
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
Kendi türünde bir üyeyi geçersiz kılarsanız, orijinal üyeye erişiminizi kaybedersiniz, buna yine de miras kullanarak süper erişim yoluyla erişebilirsiniz. Yani kalıtım kullanarak gerçekten kazanılan şey:
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
Şimdi kek kalıbının tüm inceliklerini anlayabildiğimi iddia edemem, ancak modülerliği güçlendirmenin ana yönteminin miras veya kendinden türlerden ziyade kompozisyon yoluyla olması bana çarpıcı geliyor.
Kalıtım sürümü daha kısadır, ancak kendi türlerine göre kalıtımı tercih etmemin temel nedeni, kendi kendine türlerle başlatma sırasını doğru almanın çok daha zor olduğunu görmemdir. Ancak, kalıtımla yapamayacağınız öz türlerle yapabileceğiniz bazı şeyler vardır. Kendi kendine türler bir tür kullanabilirken, kalıtım aşağıdaki gibi bir özellik veya sınıf gerektirir:
trait Outer
{ type T1 }
trait S1
{ selfS1: Outer#T1 => } //Not possible with inheritance.
Hatta şunları yapabilirsiniz:
trait TypeBuster
{ this: Int with String => }
Buna rağmen asla başaramayacaksınız. Bir türden miras kalmamak için kesin bir neden görmüyorum, ancak kesinlikle tür yapıcı sınıfları / sınıflarımız olduğu için yol yapıcı sınıfları ve özelliklerine sahip olmanın yararlı olacağını hissediyorum. Ne yazık ki
trait InnerA extends Outer#Inner //Doesn't compile
Bizde bu var:
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 }
Veya bu:
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 }
Daha fazla empati edilmesi gereken bir nokta, özelliklerin sınıfları genişletebilmesidir. David Maclver'e bunu işaret ettiği için teşekkürler. İşte kendi kodumdan bir örnek:
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
Swing Frame sınıfından miras alır , bu nedenle kendi kendine bir tür olarak kullanılabilir ve daha sonra sonunda karıştırılabilir (örnekleme sırasında). Ancak, val geomR
özellikler devralınarak kullanılmadan önce başlatılması gerekir. Bu yüzden önceden başlatılmasını sağlamak için bir sınıfa ihtiyacımız var geomR
. Sınıf ScnVista
daha sonra kendileri miras alınabilecek birden çok dikey özellikten miras alınabilir. Çoklu tip parametreleri (jenerikler) kullanmak alternatif bir modülerlik biçimi sunar.