Programming in Sala 책으로 스칼라 스터디하면서 정리했던 내용이다. 지금은 3판 번역본도 나왔지만, 약간 앞서서 스터디를 시작해서 2판으로 진행했다.

12장

트레이트 동작

  • 기본 부모 클래스는 AnyRef
trait Philosophical {
  def philosophize() {
    println("I consume memory, therefore I am!")
  }
}
  • 믹스인 : extends. 트레이트의 부모클래스를 암시적 상속
class Frog extends Philosophical {
  override def toString = "green"
}
  • 트레이트도 타입을 정의함
val phil: Philosophical = new Frog
  • 트레이트는 여러개를 믹스인 가능 : with
// 부모 클래스를 상속한 클래스에 믹스인
class Animal
class Frog extends Animal with Philosophical {
  override def toString = "green"
}

// 여러 트레이트 믹스인
trait HasLegs
class Frog extends Animal with Philosophical with HasLegs {
  override def toString = "green"
}
  • 트레이트 구현 오버라이드 가능 : override
class Animal
class Frog extends Animal with Philosophical {
  override def toString = "green"
  override def philosophize() {
    println("It ain't easy being "+ toString +"!")
  }
}

val phrog: Philosophical = new Frog
phrog.philosophize()    // 오버라이드 되었기 때문에 "It ain't easy being green!" 출력
  • 클래스 정의하면서 할 수 있는 모든 것 가능 : 트레이트에 필드 선언 등
  • '클래스' 파라미터를 가질 수 없음(생성자 파라미터 불가)
  • super 호출을 동적으로 바인딩 함(믹스인 하는 클래스에 따라 달라짐)

간결한 인터페이스 / 풍부한 인터페이스

  • 간결한 인터페이스 : 메소드 수가 적어 구현하는 측이 편리
  • 풍부한 인터페이스 : 많은 메소드 중 필요에 일치하는 메소드를 선택/사용하여 사용하는 측 편리
  • 간결한 인터페이스를 풍부한 인터페이스로 만들 때 트레이트를 사용할 수 있음
    1. 간결한 인터페이스 역할을 하는 추상 메소드 구현
    2. 추상 메소드를 활용해 풍부한 인터페이스 역할을 할 여러 메소드를 동일 트레이트 안에 구현

예제

class Point(val x: Int, val y: Int)

trait Rectangular {
  def topLeft: Point
  def bottomRight: Point

  def left = topLeft.x
  def right = bottomRight.x
  def width = right - left
  // ...
}

abstract class Component extends Rectangular {
  // ...
}

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

Orderd 트레이트

  • 순서를 표한하는 트레이트
  • 사용
    1. Ordered 트레이트를 타입 파라미터(19장) 명시하여 믹스인 Ordered[C]
    2. compare 메소드 정의
// Before
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)
}

// After
class Rational(n: Int, d: Int) extends Ordered[Rational] {
  // ...
  def compare(that: Rational) =
    (this.numer * that.denom) - (that.numer * this.denom)
}
  • equals는 직접 정의해야함(30장 우회 방법)

변경 쌓기

  • 클래스의 메소드를 변경하고, 변경 위에 다른 변경을 계속 쌓을 수 있음
abstract class IntQueue {
  def get(): Int
  def put(x: Int)
}

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 Doubling extends IntQueue {
  abstract override def put(x: Int) { super.put(2 * x) }
}

// 믹스인
class MyQueue extends BasicIntQueue with Doubling
val queue = new MyQueue
queue.put(10)
queue.get()     // 20

// 인스턴스 생성시 믹스인
val queue2 = new BasicIntQueue with Doubling
queue2.put(10)
queue2.get()    // 20
  • 여러 트레이트로 변경을 여러 순서로 쌓을 수 있음
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)
  }
}

// 음수이면 제거 후에 1 증가
val queue = (new BasicIntQueue with Incrementing with Filtering)
queue.put(-1);queue.put(0);queue.put(1)
queue.get()     // 1
queue.get()     // 2

// 1 증가 후에 음수이면 제거
val queue2 = (new BasicIntQueue with Filtering with Incrementing)
queue.put(-1);queue.put(0);queue.put(1)
queue.get()     // 0
queue.get()     // 1
queue.get()     // 2

선형화

  • 상속의 경우 super를 호출할 때에 어떤 메소드를 부를지 컴파일 시점에 이루어진다.
  • 트레이트는 선형화로 부를 메소드를 결정한다.
class Animal
trait Furry extends Animal
trait HasLegs extends Animal
trait FourLegged extends HasLegs
class Cat extends Animal with Furry with FourLegged
  1. Animal -> AnyRef -> Any
  2. Furry -> (Animal -> AnyRef -> Any) // 이미 선형화한 부분은 제외. 중복 제외
  3. FourLegged -> HasLegs -> (Furry -> Animal -> AnyRef -> Any)
  4. Cat -> (FourLegged -> HasLegs -> Furry -> Animal -> AnyRef -> Any)

super 사용시, 선형화 순서상 자기보다 바로 오른쪽에 있는 첫 번째 구현을 호출

트레이트 사용 고려 사항

  • 재사용하지 않는 경우 -> 클래스
  • 관련 없는 클래스에서 여러번 재사용 -> 트레이트
  • 자바 코드에서 스칼라 내용을 상속 -> 추상 클래스
  • 컴파일한 바이트 코드 형태로 배포 -> 추상 클래스
  • 효율이 중요 -> 클래스
  • 잘 모르겠으면 -> 트레이트


+ Recent posts