만약 숫자를 세는 actor가 있다고 생각을 해보자.
직관적으로 다음과 같은 코드를 작성할 것이다.
object CounterActor {
case object Increment
case object Decrement
case object Print
}
class CounterActor {
import CounterActor._
var count = 0
override def receive:Receive = {
case Increment => count += 1
case Decrement => count -= 1
case Print => println(s"[counter] current count is $count")
}
}
var
로 선언되어 있는 변수 count
는 들어오는 메시지에 따라 값이 변화가 될 것이다. 하지만 mutable한 부분을 최대한 줄일 수 있지 않을까? 이를 위해서는 상태가 변했을 때 message handler를 바꾸면 된다.
이렇게 메시지 핸들러를 바꿈으로써 actor 내부의 mutable한 상태를 제거할 수 있다.
위의 코드를 어떠한 방식으로 message handler를 바꾸어 mutable한 상태를 제거할 수 있을까?
object CounterActor {
case object Increment
case object Decrement
case object Print
}
class CounterActor {
import CounterActor._
override def receive:Receive = countHandler(0)
private def countHandler(count:Int) :Receive = {
case Increment => context.become(count + 1)
case Decrement => context.become(count - 1)
case Print => println(s"[counter] current count is $count")
}
}
가장 눈에 띄는 지점은 2가지일 것이다.
count
가 사라지고, 메시지 핸들러의 파라미터로 들어갔다.context.become
메서드위의 코드는 context.become
을 통해 액터의 기본 메시지 핸들러를 바꾸는 것이다. 즉, receive
와 같은 형태의 리턴 타입(PartialFunction[Any, Unit]
/ Receive
)을 가지며, 디폴트 Receive 함수를 대체할 수 있는 것이다.
위와 같은 형식의 코드는 FSM(Finite State Machine)
을 구현할 때 유용하게 사용된다.