Zoeken…


Syntaxis

  • kenmerk ATrait {...}
  • klasse AClass (...) verlengt ATrait {...}
  • klasse AClass breidt BClass uit met ATrait
  • klasse AClass breidt ATrait uit met BTrait
  • klasse AClass breidt ATrait uit met BTrait met CTrait
  • klasse ATrait verlengt BTrait

Stapelbare modificatie met eigenschappen

Je kunt eigenschappen gebruiken om methoden van een klasse te wijzigen, door eigenschappen op een stapelbare manier te gebruiken.

Het volgende voorbeeld laat zien hoe eigenschappen kunnen worden gestapeld. De volgorde van de eigenschappen is belangrijk. Met behulp van verschillende volgorde van eigenschappen, wordt verschillend gedrag bereikt.

class Ball {
  def roll(ball : String) = println("Rolling : " + ball)
}

trait Red extends Ball {
  override def roll(ball : String) = super.roll("Red-" + ball)
}

trait Green extends Ball {
  override def roll(ball : String) = super.roll("Green-" + ball)
}

trait Shiny extends Ball {
  override def roll(ball : String) = super.roll("Shiny-" + ball)
}

object Balls {
  def main(args: Array[String]) {
    val ball1 = new Ball with Shiny with Red
    ball1.roll("Ball-1") // Rolling : Shiny-Red-Ball-1

    val ball2 = new Ball with Green with Shiny
    ball2.roll("Ball-2") // Rolling : Green-Shiny-Ball-2
  }
}

Merk op dat super wordt gebruikt om de methode roll() in beide eigenschappen aan te roepen. Alleen op deze manier kunnen we stapelbare modificaties bereiken. In het geval van stapelbare modificatie, wordt de methode-aanroepvolgorde bepaald door linearisatieregel .

Basiskennis van eigenschappen

Dit is de meest eenvoudige versie van een eigenschap in Scala.

trait Identifiable {
  def getIdentifier: String
  def printIndentification(): Unit = println(getIdentifier)
}

case class Puppy(id: String, name: String) extends Identifiable {
  def getIdentifier: String = s"$name has id $id"
}

Aangezien er geen superklasse wordt verklaard voor eigenschap Identifiable , wordt deze standaard uitgebreid van de klasse AnyRef . Omdat er geen definitie voor getIdentifier wordt gegeven in Identifiable , moet de Puppy klasse deze implementeren. Puppy neemt de implementatie van printIdentification van Identifiable .

In de REPL:

val p = new Puppy("K9", "Rex")
p.getIdentifier  // res0: String = Rex has id K9
p.printIndentification()  // Rex has id K9

Het Diamond-probleem oplossen

Het diamantprobleem , of meervoudige overerving, wordt afgehandeld door Scala met behulp van eigenschappen, die vergelijkbaar zijn met Java-interfaces. Kenmerken zijn flexibeler dan interfaces en kunnen geïmplementeerde methoden bevatten. Dit maakt eigenschappen vergelijkbaar met mixins in andere talen.

Scala ondersteunt geen overerving van meerdere klassen, maar een gebruiker kan meerdere eigenschappen in een enkele klasse uitbreiden:

trait traitA {
  def name = println("This is the 'grandparent' trait.")
}

trait traitB extends traitA {
  override def name = {
    println("B is a child of A.")
    super.name
  }

}

trait traitC extends traitA {
  override def name = {
    println("C is a child of A.")
    super.name
  }
}

object grandChild extends traitB with traitC

grandChild.name

Hier grandChild van zowel traitB als traitC , die beide op hun beurt erven van traitA . De uitvoer (hieronder) toont ook de volgorde van prioriteit bij het oplossen van welke methode-implementaties het eerst worden genoemd:

C is a child of A. 
B is a child of A. 
This is the 'grandparent' trait.

Merk op dat, wanneer super wordt gebruikt om methoden in de class of trait te roepen, lineariseringsregel een rol speelt om de hiërarchie van de oproep te bepalen. Linearisatieorder voor grandChild is:

grandChild -> traitC -> traitB -> traitA -> AnyRef -> Any


Hieronder is nog een voorbeeld:

trait Printer {
  def print(msg : String) = println (msg)
}

trait DelimitWithHyphen extends Printer {
  override def print(msg : String) {
    println("-------------")
    super.print(msg)
  }
}

trait DelimitWithStar extends Printer  {
  override def print(msg : String) {
    println("*************")
    super.print(msg)
  }
}

class CustomPrinter extends Printer with DelimitWithHyphen with DelimitWithStar

object TestPrinter{
  def main(args: Array[String]) {
    new CustomPrinter().print("Hello World!")
  }
}

Dit programma drukt af:

*************
-------------
Hello World!

Linearisatie voor CustomPrinter zal zijn:

CustomPrinter -> DelimitWithStar -> DelimitWithHyphen -> Printer -> AnyRef -> Any

Linearization

In het geval van stapelbare modificatie , rangschikt Scala klassen en eigenschappen in een lineaire volgorde om de methodeaanroephiërarchie te bepalen, die bekend staat als linearisatie . De linearisatieregel wordt alleen gebruikt voor die methoden waarbij de methode wordt aangeroepen via super() . Laten we dit als voorbeeld beschouwen:

class Shape {
  def paint (shape: String): Unit = {
    println(shape)
  }
}

trait Color extends Shape {
  abstract override def paint (shape : String) {
    super.paint(shape + "Color ")
  }
}

trait Blue extends Color {
  abstract override def paint (shape : String) {
    super.paint(shape + "with Blue ")
  }
}

trait Border extends Shape {
  abstract override def paint (shape : String) {
    super.paint(shape + "Border ")
  }
}

trait Dotted extends Border {
  abstract override def paint (shape : String) {
    super.paint(shape + "with Dotted ")
  }
}

class MyShape extends Shape with Dotted with Blue {
  override def paint (shape : String) {
    super.paint(shape)
  }
}

Linearisatie gebeurt van achter naar voren . In dit geval,

  1. First Shape wordt gelineariseerd, wat eruit ziet als:

    Shape -> AnyRef -> Any

  2. Dan is Dotted gelineariseerd:

    Dotted -> Border -> Shape -> AnyRef -> Any

  3. De volgende in de rij is Blue . Normaal is de linearisatie van Blue :

    Blue -> Color -> Shape -> AnyRef -> Any

    omdat in de linearisatie van MyShape tot nu toe ( stap 2 ) Shape -> AnyRef -> Any al is verschenen. Daarom wordt het genegeerd. De Blue linearisatie zal dus zijn:

    Blue -> Color -> Dotted -> Border -> Shape -> AnyRef -> Any

  4. Ten slotte wordt Circle toegevoegd en wordt de uiteindelijke lineariseringsvolgorde:

    Cirkel -> Blauw -> Kleur -> Gestippeld -> Rand -> Vorm -> AnyRef -> Any

Deze lineariseringsvolgorde bepaalt de volgorde van methoden wanneer super wordt gebruikt in een klasse of eigenschap. De eerste methode-implementatie van rechts wordt aangeroepen, in de linearisatievolgorde. Als new MyShape().paint("Circle ") wordt uitgevoerd, wordt deze afgedrukt:

Circle with Blue Color with Dotted Border 

Meer informatie over linearisatie vindt u hier .



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow