Actors in Scala(Scala中的Actor)(预打印版) 第四章 Actor Chat (A)

Actors in Scala(Scala中的Actor)(预打印版) 第四章 Actor Chat (A)

张贵宾

guibin.beijing@gmail.com


2011.10.21

注:翻译这些英文书籍资料纯属个人爱好,如有不恰当之处敬请指正。


前面的章节展示了actor在消息传输方面的编程模型。不用惊奇,许多Scala的actor库定义了大量的处理发送消息和接收消息的编程结构。这些结构以内部领域语言(internal domain-specific language--DSL)的形式展现给了大家。本章将使用一个典型的消息应用程序:聊天程序,来向大家展示Scala的actor DSL的关键要素。


聊天程序允许用户通过对不同的主题交换消息来相互交互,每个主题代表一个聊天室,用户如果对一个聊天室主题下面的一系列讨论感兴趣的话,他便会订阅这个聊天室主题。一旦订阅了,用户可以给聊天室发送消息,反过来,他也能收到聊天室中其他订阅者发送的消息。图4.1提供了本章开发的聊天程序的概览。



4.1 Defining message classes(定义消息类)

聊天室程序的核心围绕着消息:用户发送一个Subscribe(订阅)消息代表其想要发送和接收聊天室消息。Unsubscribe(取消订阅)消息用于将用户从聊天室的对话中删除。UserPost(用户发布帖子)消息用于向聊天室发布消息。当聊天室收到了用户的UserPost消息之后,聊天室会把消息的内容转发给所有订阅了这个帖子的订阅者。聊天室会保证不会把消息转发回给发布帖子的人,避免造成“回音”效果。

典型的开发基于actor程序的方法的第一步是定义消息类,这些消息类代表了程序的通信模式。Scala的case class此时就能方便的派上用场,用case class定义actor消息。我们很快就能看到,case class在Scala的模式匹配中非常有用,模式匹配是处理actor消息的一个核心技术。下面的代码展示了如何为我们的聊天程序定义消息。

case class User(name: String)
case class Subscribe(user: User)
case class Post(msg: String)
case class UserPost(user: User, post: Post)

4.2 Processing messages(处理消息)

除了消息,在聊天程序中另外一个重要的抽象是ChatRoom。ChatRoom的主要责任是保持活跃登录用户的会话,接受来自用户的消息,把用户的消息传输给感兴趣的其他用户,如图4.2所示



聊天室订阅者的状态在作为ChatRoom的私有状态被管理,当ChatRoom收到Subscribe和UnSubscribe消息时会修改它的私有状态,这种模型展示了基于actor编程的重要概念:消息发送给actor以改变actor内部的状态,接着影响actor接下来的行为。比如,一个新的Subscribe消息会导致ChatRoom将接下来的Post消息转发给新注册的用户,影响了程序的消息流。

ChatRoom的消息处理通过扩展scala.actors.Actor实现,扩展Actor trait意味着ChatRoom将会从Actor trait中获取消息处理框架的支持,比如Actor中的mailbox。


在actor中所有的消息处理发生在 actor 方法内,下面的代码展示了如何定义actor:

import scala.actors.Actor

class ChatRoom extends Actor {
  def actor() {
    // the actor's behavior
  }
}

当调用了actor的start方法之后,定义在actor方法中的消息处理逻辑才会被启动。如下代码所示:

val chatRoom = new ChatRoom
chatRoom.start

actor消息处理中的一个关键任务是从actor的mailbox中获取下一个可用的消息。Actor中的receive方法就能完成这个任务,它首先中邮箱中删除一条消息,然后把这条消息传递给你作为参数传给receive方法的一系列模式匹配语句,(让这些模式匹配语句去处理该消息。)下面代码为ChatRoom将接受的三种消息中的每一种定义了一个模式:


class ChatRoom extends Actor {
  def act() {
    while(true) {
      receive {
        case Subscribe(user) => //处理订阅
        case Unsubscribe(user) =>//处理取消订阅
        case UserPost(user, post) => //处理发帖
      }
    }
  }
}

每一次receive方法的调用,actor都会从mailbox中取到下一个可用的消息,然后把消息传输给模式匹配的列表。每条消息会依次从上到下对每个模式进行评估,如果某个模式匹配成功,这条消息就从mailbox中被删除,这个模式之后的那些模式就不再被评估。如果没有匹配到任何模式,则消息就会留在mailbox中。


在这个例子中,ChatRoom期望收到Subscribe、Unsubscribe或者UserPost消息,当收到这三种消息时,ChatRoom将会评估模式箭头=>右边的表达式。


Scala的actor库也提供了一种快捷方式来定义和启动actor,只需要一步即可,而不需要显示的扩展Actor trait。下面的代码展示了使用简化写法的actor。

val chatRoom =
  actor{
    while(true) {
        receive {
          case Subscribe(user) => //处理订阅
          case Unsubscribe(user) =>//处理取消订阅
          case UserPost(user, post) => //处理发帖
      }
    }
  }

处理订阅消息

收到了Subscribe消息之后,ChatRoom必须把用户添加到它的订阅者列表中。首先,看起来可以在一个list中保存聊天室的订阅者,但是要注意订阅者必须能够接受来自聊天室的消息。在我们当前的设计中,当UserPost消息到达时,ChatRoom会遍历所有的订阅者,并且把消息内容发给除了发送消息者之外的所有的订阅者。


因此用户可以接受来自聊天室的消息,在订阅会话中,我们可以用actor来代表一个用户,当ChatRoom收到了Subscribe消息,它可以创建一个新的actor来代表用户,把用户和新创建的actor关联。这个actor,反过来将要处理ChatRoom发给它的Post消息,代码如下所示:

val chatRoom = new ChatRoom
chatRoom ! Subscribe(User("Bob"))
var session = Map.empty[User, Actor]
while(true) {
  receive {
    case Subscribe(user) =>
      val sessionUser = 
        actor {
          while(true) {
             self.receive {
                case Post(msg) => //Send the message to sender
             }
          }
        }
      session = session + (user -> sessionUser)
     //TODO handle the Unsubscribe message
  }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值