使用akka发送时,对象,字符串,符号有什么区别?

atl*_*ine 1 scala akka

请参见下面的代码Op1,Op2,Op3都可以作为消息时与其他演员沟通作用.

我的问题是,有什么区别,任何建议的使用方式?有些事情可能就像使用Op1更有效率或更少的字节将用于使用其中之一?我想找到一个最好的做法.

package local

import akka.actor._

object Constant {
  case object Op1
  val Op2 = "msg"
  val Op3 = 'msg
}

object Local extends App {
  implicit val system = ActorSystem("LocalSystem")
  val localActor = system.actorOf(Props[LocalActor], name = "LocalActor")
  localActor ! Constant.Op1
  localActor ! Constant.Op2
  localActor ! Constant.Op3
}

class LocalActor extends Actor {
  def receive = {
    case Constant.Op1 =>
      println("1")
    case Constant.Op2 =>
      println("2")
    case Constant.Op3 =>
      println("3")
  }
}
Run Code Online (Sandbox Code Playgroud)

Sar*_*ngh 5

嗯......"最佳实践"一词非常主观.您的问题陈述的背景通常会影响您最佳实践.因此,你应该更多地关注而why is this a best practice不是what is the best practice.

现在让我们在通用上下文中讨论它.

如您所知,Akka演员使用消息相互通信.而且你必须明白,无论何时双方之间进行通信,都需要在它们之间建立协议,这使得它们能够以不明确的方式进行通信.

此外,我们知道双方都可以决定在没有任何协议的情况下用英语进行交流,但这会引入彼此误解的可能性.

现在,当我们想要建立可靠的系统时,这种可能存在模糊性的问题是不必要的.这就是为什么我们开始在我们的演员之间建立协议.

object LaughProtocol {
  sealed trait LaughMessage

  case object Lol extends LaughMessage
  case object Rofl extends LaughMessage
  case object Lmao extend LaughMessage
}

class LaughActor extends Actor with ActorLogging{

  import LaughProtocol._

  override def receive = {
    case msg @ LaughMessage => handleLaugh(msg)
    case msg @ _ => log.info("unexpected message :: {}", msg)
  }

  def handleLaugh(msg: LaughMessage) = {
    case Lol => println("L O L")
    case Rofl => println("R O F L")
    case Lmao => println("L M A O")
  }

}
Run Code Online (Sandbox Code Playgroud)

这使我们能够确定我们将要处理的消息的本质的简单性.另外......对于任何其他与之沟通的演员来说LaughActor,它明确规定了与之沟通的规则LaughActor.

现在......你会说只是将这些定义为错误Strings.

class LaughActor extends Actor with ActorLogging{

  override def receive = {
    case "Lol" => println("L O L")
    case "Rofl" => println("R O F L")
    case "Lmao" => println("L M A O")
    case msg @ _ => log.info("unexpected message :: {}", msg)
  }

}
Run Code Online (Sandbox Code Playgroud)

您可以争辩说,即使在这种情况下,任何开发人员都可以查看此actor的代码并找出协议.虽然它们确实可以,但是在查看跨越数十个文件的真实世界代码时......它变得非常困难.

不仅如此......在编写正确的代码时,你失去了一个最重要的帮助者compiler.只需考虑以下来自潜在用户的行LaughActor.

// case 1 - With sealed hierarchy of messages
laughActorRef ! LuaghProtocol.Lol

// case 2 - with strings,
laughActorRef ! "lol"
Run Code Online (Sandbox Code Playgroud)

如果开发人员犯了错误而写了以下而不是上面的内容会怎么样

    // case 1 - With sealed hierarchy of messages
laughActorRef ! LuaghProtocol.Loll

// case 2 - with strings,
laughActorRef ! "loll"
Run Code Online (Sandbox Code Playgroud)

在第一种情况下,编译器将立即指出错误...但在第二种情况下,此错误将通过未注意到,并且当隐藏在数万行的代码库中时可能会导致很多头痛的调试.

但是再次......你甚至可以通过仅使用预定义的字符串来避免这个问题

object LaughProtocol {
  val Lol = "Lol"
  val Rofl = "Rofl"
  val Lmao = "Lmao"
}

class LaughActor extends Actor with ActorLogging{

  import LaughProtocol._

  override def receive = {
    case msg if msg.equals(LaughProtocol.Lol) => println("L O L")
    case msg if msg.equals(LaughProtocol.Rofl) => println("R O F L")
    case msg if msg.equals(LaughProtocol.Lmao) => println("L M A O")
    case msg @ _ => log.info("unexpected message :: {}", msg)
  }
}
Run Code Online (Sandbox Code Playgroud)

但是......考虑一个由5-6名开发人员组成的数十名演员编写的更大的应用程序.

请注意......到目前为止,开发人员完全依赖于定义的成员LaughProtocol.Lmao等......而且他们实际上并没有看到等值LaughProtocol.Lmao有什么价值.

现在......让我们说另一个演员有如下的协议,

object LoveProtocol {
  val LotsOfLove = "Lol"
}
Run Code Online (Sandbox Code Playgroud)

现在......你应该能够注意到这个问题.考虑任何应该处理这两种协议的消息的actor的情况.所有它将收到的是一个字符串Lol,它将无法知道它是否是一个LaughProtocol.Lol或LoveProtocol.LotsOfLove.

所以......现在每当开发人员向任何协议添加任何新消息时,他都需要确保没有其他协议使用相同的协议String.对于从事大型代码工作的团队来说,这根本不是一个选择.

这些只是为什么人们更喜欢sealed protocols代码库中的东西的原因.