【2019-05-23】特質trait

7261 ワード

特質はScalaのコード多重化の基礎ユニットである.特質はメソッドとフィールドの定義をカプセル化し、クラスに混入して再利用することができます.特質の定義はキーワードtraitを用いる以外はクラス定義と変わらない.
trait Philosophical {
  def philosophize() {
    println("I consume memory, therefore I am!")
  }
}

extendsを用いて特質を混入する
class Frog extends Philosophical {
    override def toString = "green"
  }
//Frog  AnyRef(Philosophical   )      Philosophical
//                       
val frog=new Frog
//frog: Frog = green
//Phil    Philosophical,   ,  Phil            Philosophical       
val phil:Philosophical=frog
//phil: Philosophical = green
frog.philosophize()
//I consume memory, therefore I am!

使用with混入特質
object Ex1 {
  class Animal
  
  class Frog extends Animal with Philosophical {
    override def toString = "green"
  }

  def main(args: Array[String]) {
    println("new Frog [" + (new Frog) + "]")
  }
}

複数の特質を混入する
class Animal
trait HasLegs

class Frog extends Animal with Philosophical with HasLegs {
  override def toString = "green"
}

痩せインタフェース対肥満インタフェースの特質の1つの主要な応用方式はクラスの既存の方法によって自動的にクラスに方法を追加することができて、すなわち:特質は1つのやせインタフェースを豊かにすることができて、それを太ったインタフェースに変えることができます.
object Ex2 {
  class Animal
  
  class Frog extends Animal with Philosophical {
    override def toString = "green"
    override def philosophize() {
      println("It ain't easy being "+ toString +"!")
    }
  }

  class Point(x: Int, y: Int)
  trait CharSequence {
    def charAt(index: Int): Char
    def length: Int
    def subSequence(start: Int, end: Int): CharSequence
    def toString(): String
  }
  trait Ordered[T] {
    def compare(that: T): Int
  
    def (that: T): Boolean = (this compare that) > 0
    def <=(that: T): Boolean = (this compare that) <= 0
    def >=(that: T): Boolean = (this compare that) >= 0
  }

  import scala.collection.mutable.ArrayBuffer
  
  class BasicIntQueue extends IntQueue {
    private val buf = new ArrayBuffer[Int]
    def get() = buf.remove(0)
    def put(x: Int) { buf += x }
  }
  trait Incrementing extends IntQueue {
    abstract override def put(x: Int) { super.put(x + 1) }
  }
  trait Doubling extends IntQueue {
    abstract override def put(x: Int) { super.put(2 * x) }
  }

  def main(args: Array[String]) {
    (new Frog).philosophize()

    // Multiple inheritance thought experiment
    val q = new BasicIntQueue with Incrementing with Doubling
    q.put(42)  // which put would be called?
    println("q [" + q + "]")
  }
}

長方形オブジェクト
class Point(val x: Int, val y: Int)

 class Rectangle(val topLeft: Point, val bottomRight: Point) {
    def left = topLeft.x
    def right = bottomRight.x
    def width = right - left
  }

abstract class Component {
    def topLeft: Point
    def bottomRight: Point
    def left = topLeft.x
    def right = bottomRight.x
    def width = right - left
  }


trait Rectangular {
  def topLeft: Point
  def bottomRight: Point
  def left = topLeft.x
  def right = bottomRight.x
  def width = right - left
}

class Rectangle(val topLeft: Point, val bottomRight: Point)
    extends Rectangular {
}

val rect = new Rectangle(new Point(1, 1),new Point(10, 10))
//rect: Rectangle = Rectangle@5128197f
rect.left
//res2: Int = 1
rect.right
//res3: Int = 10
rect.width
//res4: Int = 9

ordered特質
//     ,4      、<=、>=
class Rational(n: Int, d: Int) {
    def < (that: Rational) = 
      this.numer * that.denom > that.numer * this.denom
    def > (that: Rational) = that < this
    def <= (that: Rational) = (this < that) || (this == that)
    def >= (that: Rational) = (this > that) || (this == that)
  }

//  ordered   Rational      
//     compare             ,ordered           、<=、>=
class Rational(n: Int, d: Int) extends Ordered[Rational] {
  def compare(that: Rational) =
    (this.numer * that.denom) - (that.numer * this.denom)

  require(d != 0)

  private val g = gcd(n.abs, d.abs)
  val numer = n / g
  val denom = d / g

  def this(n: Int) = this(n, 1)

  def + (that: Rational): Rational =
    new Rational(
      numer * that.denom + that.numer * denom,
      denom * that.denom
    )

  def + (i: Int): Rational =
    new Rational(numer + i * denom, denom)

  def - (that: Rational): Rational =
    new Rational(
      numer * that.denom - that.numer * denom,
      denom * that.denom
    )

  def - (i: Int): Rational =
    new Rational(numer - i * denom, denom)

  def * (that: Rational): Rational =
    new Rational(numer * that.numer, denom * that.denom)

  def * (i: Int): Rational =
    new Rational(numer * i, denom)

  def / (that: Rational): Rational =
    new Rational(numer * that.denom, denom * that.numer)

  def / (i: Int): Rational =
    new Rational(numer, denom * i)

  override def toString = numer +"/"+ denom

  private def gcd(a: Int, b: Int): Int = 
    if (b == 0) a else gcd(b, a % b)

  override def equals(other: Any): Boolean =
    other match {

      case that: Rational =>
        (that canEqual this) &&
        numer == that.numer &&
        denom == that.denom

      case _ => false
    }

  def canEqual(other: Any): Boolean =
    other.isInstanceOf[Rational]

  override def hashCode: Int =
    41 * (
      41 + numer
    ) + denom
}

特質は積み重ね可能な変更に用いられる
//IntQueue   put           , get         
abstract class IntQueue {
  def get(): Int
  def put(x: Int)
}


object Ex2 {
  class Animal
  
  class Frog extends Animal with Philosophical {
    override def toString = "green"
    override def philosophize() {
      println("It ain't easy being "+ toString +"!")
    }
  }

  class Point(x: Int, y: Int)
  trait CharSequence {
    def charAt(index: Int): Char
    def length: Int
    def subSequence(start: Int, end: Int): CharSequence
    def toString(): String
  }
  trait Ordered[T] {
    def compare(that: T): Int
  
    def (that: T): Boolean = (this compare that) > 0
    def <=(that: T): Boolean = (this compare that) <= 0
    def >=(that: T): Boolean = (this compare that) >= 0
  }

  import scala.collection.mutable.ArrayBuffer
  //  ArrayBuffer  BasicIntQueue 
  class BasicIntQueue extends IntQueue {
    private val buf = new ArrayBuffer[Int]
    def get() = buf.remove(0)
    def put(x: Int) { buf += x }
  }
val queue = new BasicIntQueue
//queue: BasicIntQueue = BasicIntQueue@3e1c58c9
queue.put(10)
queue.put(20)
queue.get()
//res17: Int = 10
queue.get()
//res18: Int = 20

//       Incrementing  Filtering 
  trait Incrementing extends IntQueue {
    abstract override def put(x: Int) { super.put(x + 1) }
  }
trait Filtering extends IntQueue {
    abstract override def put(x: Int) {
      if (x >= 0) super.put(x)
    }
  }
//         
//Doubling       
  trait Doubling extends IntQueue {
    abstract override def put(x: Int) { super.put(2 * x) }
  }

  def main(args: Array[String]) {
    (new Frog).philosophize()

    //         
    val q = new BasicIntQueue with Incrementing with Doubling
    q.put(42)  //     put
    println("q [" + q + "]")
  }
}