#scala #actor #akka
#scala #актер #akka
Вопрос:
В большинстве примеров правильного использования фреймворков акторов scala (и akka) люди склонны выводить каждое сообщение из одной черты. Например:
trait Message
object Ping extends Message
object Pong extends Message
Однако как в Scala, так и в Akka прием сообщений вообще не типизирован. Есть ли какая-либо причина для реализации общей черты?
Ответ №1:
Это действительно зависит от того, чего вы пытаетесь достичь. Например, я недавно создал небольшое приложение, используя участников, у которых было несколько типов участников, и управляющий участник, который действовал более или менее как маршрутизатор. Теперь работающие участники могут получать множество разных сообщений, например Foo
, Bar
и Baz
. Без супертипа в управляющем актере мне пришлось бы написать что-то вроде этого:
react {
case x:Foo | x:Bar | x:Baz => worker ! x
}
Что, очевидно, излишне многословно. Итак, в этом случае супертип WorkerMessage
имел бы большой смысл, потому что это упрощает ваш код:
react {
case x:WorkerMessage => worker ! x
}
С другой стороны, это делает сообщения Foo
, Bar
и Baz
практически непригодными для любых других целей, кроме использования вашими WorkerActors. Например, если бы у вас было сообщение Stop
или Init
, это, вероятно, было бы плохо, потому что вам нужно было бы переопределять его повсюду.
Итак, если вы знаете, что у вас будут только актеры, которые не передают сообщения (то есть они обрабатывают их сами), то, я думаю, вы прекрасно обойдетесь без супертипа для них.
Я предполагаю, что причина, по которой люди делают это более или менее по умолчанию, заключается в том, что если вы позже измените свой код, вам не придется впоследствии создавать черту, потому что вы уже сделали это в начале.
Лично я всегда стараюсь избегать ненужных накладных расходов, поэтому я бы, вероятно, не стал определять супертип, если мне это действительно не нужно. Кроме того, я действительно не знаю, влияет ли создание супертипа вообще на производительность, но мне было бы интересно узнать.
Ответ №2:
-
Как с помощью
scala.actors
(черезInputChannel[T]
илиReactor[T]
), так и Akka (TypedActor
) вы можете установить границы типов для входящих сообщений; -
В большинстве примеров сообщения расширяют
sealed trait
. Это сделано по двум причинам:-
если обработчик сообщений (частичная функция) вашего участника не охватывает все сообщения, которые расширяют черту, компилятор генерирует предупреждение;
-
sealed trait
может быть расширено только в исходном файле, где определена черта, и, таким образом, клиент не может определить свои собственные сообщения, которые расширяют черту;
-
Комментарии:
1. Хорошо, теперь я понимаю причину scala.actors. Однако для актеров, типизированных akka, вы не определяете сообщения, вы просто вызываете свои методы интерфейса и ждете, когда произойдет волшебство. Запечатанный признак полезен, но опять же, если я правильно помню, Akka receive является частичной функцией [Any, Unit], поэтому нет проверки на пропущенные случаи.
Ответ №3:
Это не обязательно, но это материал для OO-дизайна. Для сообщений домена вашего приложения лучше иметь абстрактный тип. Таким образом, вы можете воспользоваться преимуществами полиморфизма при работе с сообщениями в коде нашего приложения.
trait Message
object Ping extends Message
objet Pong extends Message
object Stop
Например, если где-то в вашем приложении вам приходится иметь дело с кучей сообщений, независимо от их конкретных типов (Ping или Понг), вы будете рассматривать их все как объекты типа Message.
Это имеет смысл? Нет?
Комментарии:
1. Если есть несколько черт для реализации, это может иметь смысл. Но ваш аргумент недействителен, если все сообщения реализуют одну и ту же родительскую черту.