这是一个更一般的设计问题,关于如何为 akka 演员建模。这种情况在一个非常简单的例子中得到了解释,我想得到一个关于可能性和方法以及它们的优缺点的更一般的答案。
有一个用户对象应该做一些事情。可以说:doSomethingWithUser(user: User)
。假设用户有avatar: Option[String]
一个 url 属性。如果存在,则应在运行该doSomethingWithUser
方法之前抓取 url 后面的实际图像。说 Akka,我会创建一个DoSomethingWithUserActor
可以接收两条消息的 Actor:
case class NewUser(user: User)
case class NewUserWithImage(user: User, imageData: Array[Byte])
FetchImageActor
抓取图像数据被实现为一个可以处理一条消息的 Actor :
case class FetchImage(url: String)
并产生一条消息:
case class GotImage(imageData: Array[Byte])
是根MainActor
参与者,只接收一条消息NewUser
,处理方式如下:
def receive {
case newUser: NewUser => {
newUser.avatar match {
case Some(avatar) => {
// here I would like to send a message to the FetchImageActor,
// wait for the response (GotImage) and once it's there send a
// NewUserWithImage message to the DoSomethingWithUser actor.
//
// How can this be done?
// Is it a good idea to use a Future here, and if so, how can this
// be done?
//
// pseudocode:
val gotImage: GotImage = // get it somehow
doSomethingWithUserActor ! NewUserWithImage(newUser.user, gotImage.imageData)
}
case _ => doSomethingWithUserActor forward NewUser(newUser.user)
}
}
DoSomethingWithUserActor
处理消息NewUser
和. NewUserWithImage
也许是这样的:
def receive {
case newUser: NewUser => doSomethingWithUser(newUser.user)
case newUserWithImage: NewUserWithImage => {
doSomethingWithImage(newUserWithImage.imageData)
doSomethingWithUser(newUser.user)
}
}
private def doSomethingWithUser(user: User) = { ... }
private def doSomethingWithImage(imageData: Array[Byte]) = { ... }
首先,我不知道如何在用户有头像的情况下进行异步调用,其次,我不知道通常以这种方式处理这个问题是否是一种好方法。
另一种方法可能是将 NewUser 消息转发到 FetchImageActor。这个actor然后检查用户是否设置了头像属性,如果是,它获取图像并将NewUserWithImage消息发送回MainActor,MainActor将此消息转发给DoSomethingWithUserActor,然后它实际上对包含的用户对象和图像做一些事情数据。我想,这会很糟糕,因为 FetchImageActor 需要有关用户的知识,但它仅用于获取图像。那是两个不同的独立方面,不应混为一谈。在这种情况下,FetchImage
消息对象也需要用户属性(我不喜欢前面描述的)。
解决这个问题的正确或“好”策略是什么?