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
호출을 동적으로 바인딩 함(믹스인 하는 클래스에 따라 달라짐)
간결한 인터페이스 / 풍부한 인터페이스
- 간결한 인터페이스 : 메소드 수가 적어 구현하는 측이 편리
- 풍부한 인터페이스 : 많은 메소드 중 필요에 일치하는 메소드를 선택/사용하여 사용하는 측 편리
- 간결한 인터페이스를 풍부한 인터페이스로 만들 때 트레이트를 사용할 수 있음
- 간결한 인터페이스 역할을 하는 추상 메소드 구현
- 추상 메소드를 활용해 풍부한 인터페이스 역할을 할 여러 메소드를 동일 트레이트 안에 구현
예제
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 트레이트
- 순서를 표한하는 트레이트
- 사용
- Ordered 트레이트를 타입 파라미터(19장) 명시하여 믹스인
Ordered[C]
compare
메소드 정의
- Ordered 트레이트를 타입 파라미터(19장) 명시하여 믹스인
// 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
- Animal -> AnyRef -> Any
- Furry -> (Animal -> AnyRef -> Any) // 이미 선형화한 부분은 제외. 중복 제외
- FourLegged -> HasLegs -> (Furry -> Animal -> AnyRef -> Any)
- Cat -> (FourLegged -> HasLegs -> Furry -> Animal -> AnyRef -> Any)
super
사용시, 선형화 순서상 자기보다 바로 오른쪽에 있는 첫 번째 구현을 호출
트레이트 사용 고려 사항
- 재사용하지 않는 경우 -> 클래스
- 관련 없는 클래스에서 여러번 재사용 -> 트레이트
- 자바 코드에서 스칼라 내용을 상속 -> 추상 클래스
- 컴파일한 바이트 코드 형태로 배포 -> 추상 클래스
- 효율이 중요 -> 클래스
- 잘 모르겠으면 -> 트레이트
'Developing' 카테고리의 다른 글
Programming in Scala 스터디 정리 - 13장. 패키지와 임포트 (0) | 2017.09.21 |
---|---|
Programming in Scala 스터디 정리 - 11장. 스칼라의 계층구조 (0) | 2017.09.17 |
Programming in Scala 스터디 정리 - 10장. 상속과 구성 (0) | 2017.06.16 |