Как избежать мутации переменной состояния в актере Akka с унаследованным поведением? - PullRequest
1 голос
/ 22 января 2020

У меня есть некоторые актеры Акки с обычным поведением. Это общее поведение определено в признаке:

trait CommonBehavior {
  this: Actor =>
  var history: List[String] = Nil
  protected def commonActions: Receive = {
    case Action1 => history = "action1" :: history.take(99)
    case Action2 => history = "action2" :: history.take(99)
    case GetHistory => sender() ! history
  }
}

Актеры переопределяют эту черту и определяют дополнительное поведение с помощью orElse. Вот один из примеров такого субъекта:

class MyActor extends Actor with CommonBehavior {
  var state: Int = 0
  override def receive: Receive =
    commonActions orElse {
      case Increment => state += 1
      case Decrement => state -= 1
    }
}

Я знаю, что изменяет состояние - это антипаттерн , и я хочу реорганизовать его с использованием context.become. Проблема в том, что при изменении состояния в MyActor с помощью context.become я не знаю параметра для commonActions. Можно ли даже унаследовать поведение? Нужен ли мне больший рефактор (например, создание прокси-актера)? Вот как далеко я продвинулся:

trait CommonBehavior {
  this: Actor =>
  protected def commonActions(history: List[String]): Receive = {
    case Action1 => context.become(??? orElse commonActions("action1" :: history.take(99))
    case Action2 => context.become(??? orElse commonActions("action2" :: history.take(99))
    case GetHistory => sender() ! history
  }
}

class MyActor extends Actor with CommonBehavior {
    override def receive = ready(0)
  def ready(state: Int): Receive = {
    case Increment => context.become(ready(state + 1) orElse commonActions(???))
    case Decrement => context.become(ready(state - 1) orElse commonActions(???))
  } orElse commonActions(Nil)
}

Ответы [ 2 ]

1 голос
/ 23 января 2020

Состояние мутации в актере не является антипаттерном, хорошо делать больше актеров в стиле OO (и в случаях с высокой пропускной способностью может быть более производительным), которые изменяют состояние в ответ на сообщения. Решение сделать более FP-стиль - это личное предпочтение, поэтому подумайте о плюсах и минусах вашего варианта использования (ваш опыт, опыт работы в команде, размер проекта и т. Д. c), а не следуйте догадкам кого-либо. Особенно, если у вас уже есть иерархия классов, которая ожидает, что вы будете делать мутации, а не переключать поведение.

Если вы решите, что хотите сделать актера в стиле FP, я бы рекомендовал пересмотреть всю структуру и не иметь mixin с изменяемым состоянием, для начала требующий смешивания с Actor, но дизайн с этой точки зрения. Я также рекомендовал бы использовать новые типизированные API, так как сторона "FP: y" дает гораздо более приятный опыт, чем использование become с классовыми c Actor API.

0 голосов
/ 22 января 2020

Как я понял, вы хотите избежать мутации состояния внутри актера, изменяя контекст актера. Итак, есть 2 возможности:

  1. Если вы боитесь изменить состояние в актере, вы можете go с этим, так как мутация внутри актера в порядке и не приводит к вопросам параллелизма. Это потому, что актеры работают синхронно.

  2. Если вы все еще хотите сохранить состояние неизменным (val) и разрешить изменение состояния во время выполнения, вы можете сделать это с помощью становления. Если вы не знаете параметров для commonActions, вы можете либо инициализировать его значением по умолчанию, либо выбрать его из хранилища в зависимости от бизнес-логики c, а затем обновить соответствующим образом.

...