Tour of Scala

Kompozicija mixin klasa

Language

Mixini su trejtovi koji se koriste za kompoziciju klase.

abstract class A {
  val message: String
}
class B extends A {
  val message = "I'm an instance of class B"
}
trait C extends A {
  def loudMessage = message.toUpperCase()
}
class D extends B with C

val d = new D
d.message  // I'm an instance of class B
d.loudMessage  // I'M AN INSTANCE OF CLASS B

Klasa D je nadklasa od B i mixina C. Klase mogu imati samo jednu nadklasu alid mogu imati više mixina (koristeći ključne riječi extends i with respektivno). Mixini i nadklasa mogu imati isti nadtip.

Pogledajmo sada zanimljiviji primjer počevši od apstraktne klase:

abstract class AbsIterator {
  type T
  def hasNext: Boolean
  def next(): T
}

Klasa ima apstraktni tip T i standardne metode iteratora. Dalje, implementiraćemo konkretnu klasu (svi apstraktni članovi T, hasNext, i next imaju implementacije):

class StringIterator(s: String) extends AbsIterator {
  type T = Char
  private var i = 0
  def hasNext = i < s.length
  def next() = {
    val ch = s charAt i
    i += 1
    ch
  }
}

StringIterator prima String i može se koristiti za iteraciju nad Stringom (npr. da vidimo da li sadrži određeni karakter).

trait RichIterator extends AbsIterator {
  def foreach(f: T => Unit) { while (hasNext) f(next()) }
}

Kreirajmo sada trejt koji također nasljeđuje AbsIterator.

trait RichIterator extends AbsIterator {
  def foreach(f: T => Unit): Unit = while (hasNext) f(next())
}

Pošto je RichIterator trejt, on ne mora implementirati apstraktne članove AbsIteratora.

Željeli bismo iskombinirati funkcionalnosti StringIteratora i RichIteratora u jednoj klasi.

object StringIteratorTest extends App {
  class Iter extends StringIterator("Scala") with RichIterator
  val iter = new Iter
  iter foreach println
}

Nova klasa Iter ima StringIterator kao nadklasu i RichIterator kao mixin.

S jednostrukim nasljeđivanjem ne bismo mogli postići ovaj nivo fleksibilnosti.