Непосредственный вопрос, возникающий из этого «паттерна»: что произойдет, если Actor
будет добавлен к actorSystem
дважды:
actorSystem.actorOf(Props(MonitorActor))
actorSystem.actorOf(Props(MonitorActor))
Это не тривиальный вопрос. В больших базах кода может быть несколько файлов / пакетов, в которых материализован Actor, поэтому приведенный выше сценарий, скорее всего, возникнет, хотя бы случайно.
В лучшем случае каждый SomeEvent
обрабатывается дважды по одной и той же логике. В худшем случае вы попадете в неприятные условия гонки с isEnough
. Итак, давайте предположим, лучший случай.
Даже в лучшем случае каждый SomeEvent будет обрабатываться по той же логике. Это неплохо в примере вопроса, потому что members
- это Set
. Но если бы это был List
, вы бы начали получать двойные вставки одного и того же события.
Другая проблема заключается в том, чтобы защищать себя от условий гонки, связанных с members
. Хорошая причина для members
быть AtomicReference
состоит в том, чтобы разрешить ситуацию, когда два «независимых» субъекта пытаются получить доступ к members
одновременно. Но это идет вразрез со всей целью актерской модели. Из оригинального формализма 1973 года (выделено мной):
Архитектура является общей по отношению к структуре управления и делает
не иметь или не нуждаться в примитивах goto, interrupt или семафор .
Аналогичное описание можно найти во введении к документации akka (выделено мной):
Модель актера обеспечивает более высокий уровень абстракции для письма.
параллельные и распределенные системы. Это облегчает разработчику от
приходится иметь дело с явной блокировкой и управлением потоками , делая это
проще писать правильные параллельные и параллельные системы.
Итак, мы фактически нарушили каркас модели Actor, и все, что мы получили, - это не необходимость вызывать конструктор. Сравните код примера вопроса с «предпочтительной» реализацией:
class MonitorActor() extends Actor {
val members: Set[String] = Set.empty[String]
eventBus.subscribe(classOf[SomeEvent])
var isEnough = false
override def receive: Receive = {
case SomeEvent(member: String) => {
members add member
isEnough = members.size >= 10
}
}
}
Теперь разработчику не нужно беспокоиться о семафорах, условиях гонки, конфликте потоков, ... Вся логика и функциональность в Actor могут быть поняты с последовательной точки зрения.