1

我有一些具有共同行为的 Akka 演员。这种常见行为在 trait 中定义:

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
  }
}

Actor 覆盖了这个 trait 并定义了额外的行为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. 问题是,当用 更改状态时MyActorcontext.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)
}
4

2 回答 2

1

改变一个actor中的状态不是一种反模式,可以做更多的OO风格的actor(并且在高吞吐量的情况下可以提高性能)来改变状态以响应消息。决定采用更多的 FP 风格是个人偏好,因此请考虑您的用例(您的经验、团队经验、项目规模等)的利弊,而不是教条地遵循某人的意见。特别是如果您已经有一个期望您进行突变而不是切换行为的类层次结构。

如果你决定做一个更 FP 风格的演员,我建议重新考虑整个结构,不要有一个可变状态的 mixin,需要从一个Actor开始但从这个角度进行设计。我还建议使用新的类型化 API,因为它们的“FP:y”方面提供了比使用become经典 Actor API 更好的体验。

于 2020-01-23T09:08:54.573 回答
-2

据我了解,您希望通过更改参与者的上下文来避免参与者内的状态突变。所以,有两种可能:

  1. 如果你害怕改变 actor 中的状态,你可以这样做,因为 actor 中的突变很好并且不会导致并发问题。这是因为演员同步工作。

  2. 如果您仍想保持状态不可变 (val) 并允许在运行时更改状态,您可以使用 become。如果您不知道 commonActions 的参数,您可以使用默认值对其进行初始化,也可以根据业务逻辑从存储中选择该值,然后进行相应更新。

于 2020-01-22T12:44:39.643 回答