访问akka / scala中actor之外的不可变成员

时间:2014-12-21 09:04:43

标签: scala akka immutability actor future

我刚开始学习Akka / Scala,我写了一个小型聊天服务器。

想象一下,这是一个基于房间的聊天服务器,每个人都可以创建自己的房间,可以同时在几个房间。每当房间里的房间用完时,房间就会关闭。房间由id: Int标识,并且具有不可变name: String。我写了下面的代码来介绍房间。

class Room(val id: Int, val name: String, var host: ActorRef) extends Actor {
  def receive = {
    case GetId() =>
      sender ! id
    case GetName() =>
      sender ! name
    case AddMember(member) => ...
    case RemoveMember(member) => ...
    case BroadcastMessage(from, message) => ...
}

现在,客户需要所有房间的ID和名称才能决定加入哪个房间。

val rooms: List[ActorRef] // Obtained somewhere
val getIdFutures: List[Future[Int]] = rooms.map { (_ ? GetId()).mapTo[Int] }
val getNameFutures: List[Future[String]] = rooms.map { (_ ? GetName()).mapTo[String] }
val getIds: Future[List[Int]] = Future.sequence(getIdFutures)
val getNames: Future[List[String]] = Future.sequence(getNameFutures)
for (ids <- getIds; names <- getNames) yield {
  ids zip names map { pair =>
    val id = pair._1
    val name = pair._2
    println(s"$id: $name")
  }
}

好吧,好吧,它有效......但是......有没有办法让我更方便地访问Actor内的不可变成员?我试图为房间演员制作一个包装器,如下面的代码:

case class RoomWrapper(val id: Int, val name: String, actor: ActorRef)

似乎很好,但是有一个问题:现在我必须在任何地方传递RoomWrapper对象。如何在房间被毁时收到通知?我不能context.watch一个RoomWrapper

如何解决这个问题?我有可能这样写吗?

val rooms: List[ActorRef]
rooms map { room =>
  println(room.id)
  println(room.name)
}

1 个答案:

答案 0 :(得分:2)

嗯,这只是我的意见。我不认为你应该按照你的建议去做,因为那样会使你的代码“多样化”(我的意思是,从演员模型中变成更具体的东西)。从技术上讲,演员不应该共享任何州,而且他们应该只对事件(消息)做出反应。无论如何,使用for comprehension可以将上面的内容重写为:

for {
  room <- rooms
  id <- (room ? GetId).mapTo[Int]
  name <- (room ? GetName).mapTo[String]
} {
  println(id)
  println(name)
}

此外,您可以创建一条消息,将id和name作为元组返回,依此类推。可能性是无限的,但我不允许以这种方式直接访问甚至是不可变状态,因为它使我对编码进入应用程序的特定模式的视觉有点混乱。