Подтвердить что ты не робот

Как мне лучше всего общаться с актерами Акки?

У меня есть два аккера Akka, которые одинаково реагируют на некоторые сообщения, но другие по-другому. Они оба отвечают на один и тот же набор сообщений. Интересно, как создавать двух моих актеров с помощью своих методов приема, через наследование, самообладание и т.д.? Я попытался объединить частичные функции из других признаков с помощью "orElse", который, к сожалению, предоставляет класс его функциональности, плюс я не был уверен, как полученный признак может легко получить доступ к контексту актера. Капля-в, модульное решение было бы идеальным, но мне интересно, если это проблема решена где-то?

4b9b3361

Ответ 1

На самом деле существует множество способов, которыми вы можете это сделать. Я перечислил два из метода OO (похоже на то, что предлагает @Randal Schulz) и еще один функциональный способ. Для первого возможного решения вы можете сделать что-то простое:

case class MessageA(s:String)
case class MessageB(i:Int)
case class MessageC(d:Double)

trait MyActor extends Actor{

  def receive = {
    case a:MessageA =>
      handleMessageA(a)

    case b:MessageB =>
      handleMessageB(b)

    case c:MessageC =>
      handleMessageC(c)
  }

  def handleMessageA(a:MessageA)

  def handleMessageB(b:MessageB) = {
    //do handling here
  }

  def handleMessageC(c:MessageC)
}

class MyActor1 extends MyActor{
  def handleMessageA(a:MessageA) = {}
  def handleMessageC(c:MessageC) = {}
}

class MyActor2 extends MyActor{
  def handleMessageA(a:MessageA) = {}
  def handleMessageC(c:MessageC) = {}
}

При таком подходе вы определяете в основном абстрактного actor impl, где функция receive определена для всех обработанных сообщений. Сообщения делегируются def, где будет реальная бизнес-логика. Два абстрактных, позволяя конкретным классам определять обработку, и один полностью реализован для случая, когда логика не должна различаться.

Теперь вариант для этого подхода с использованием шаблона стратегии:

trait MessageHandlingStrategy{
  def handleMessageA(a:MessageA)

  def handleMessageB(b:MessageB) = {
    //do handling here
  }

  def handleMessageC(c:MessageC)
}

class Strategy1 extends MessageHandlingStrategy{
  def handleMessageA(a:MessageA) = {}
  def handleMessageC(c:MessageC) = {}  
}

class Strategy2 extends MessageHandlingStrategy{
  def handleMessageA(a:MessageA) = {}
  def handleMessageC(c:MessageC) = {}  
}

class MyActor(strategy:MessageHandlingStrategy) extends Actor{

  def receive = {
    case a:MessageA => 
      strategy.handleMessageA(a)

    case b:MessageB =>
      strategy.handleMessageB(b)

    case c:MessageC =>
      strategy.handleMessageC(c)
  }
}

Здесь подход заключается в передаче в классе стратегии во время построения, который определяет обработку для a и c, причем b снова обрабатывается одинаково независимо. Эти два подхода довольно похожи и достигают одной и той же цели. Последний подход использует частичную цепочку функций и может выглядеть так:

trait MessageAHandling{
  self: Actor =>
  def handleA1:Receive = {
    case a:MessageA => //handle way 1
  }
  def handleA2:Receive = {
    case a:MessageA => //handle way 2
  }  
}

trait MessageBHandling{
  self: Actor =>
  def handleB:Receive = {
    case b:MessageB => //handle b
  }  
}

trait MessageCHandling{
  self: Actor =>
  def handleC1:Receive = {
    case c:MessageC => //handle way 1
  }
  def handleC2:Receive = {
    case c:MessageC => //handle way 2
  }  
}

class MyActor1 extends Actor with MessageAHandling with MessageBHandling with MessageCHandling{
  def receive = handleA1 orElse handleB orElse handleC1
}

class MyActor2 extends Actor with MessageAHandling with MessageBHandling with MessageCHandling{
  def receive = handleA2 orElse handleB orElse handleC2
}

Здесь показаны некоторые признаки, которые определяют поведение обработки сообщений для 3 типов сообщений. Конкретные участники смешиваются в этих чертах, а затем выбирают, какое поведение они хотят, создавая свою функцию receive, используя частичную цепочку функций.

Есть, вероятно, много других способов сделать то, что вы ищете, но я просто подумал, что я брошу несколько вариантов для вас. Надеюсь, поможет.

Ответ 2

До сих пор у меня не было оснований сожалеть о том, что фактическая функциональность моих сервисов (так называемая "бизнес-логика" ) в нижнем слое, "обычной" и синхронной (и иногда блокирующей) библиотеке, которая может быть единичное тестирование без осложнений участников. Единственное, что я помещаю в классах Actor, - это совместное долгосрочное изменяемое состояние, в котором действует этот обычный библиотечный код. Это, конечно, и логика декодирования и отправки сообщений функции Akka Actor receive.

Если вы это сделаете, использование логики в том виде, в котором вы ищете, тривиально.