Существует общий недостаток для действующих лиц: их трудно расширить. При использовании нормальных качеств вы можете легко объединить их, чтобы построить объект, который реализует оба интерфейса
trait One {
def callOne(arg : String)
}
trait Two {
def callTwo(arg : Double)
}
trait Both extends One with Two
Both
черт поддерживает два вызова в сочетании с двух признаков.
Если вы используете актерный подход, который обрабатывает сообщения вместо того, чтобы делать прямые звонки, вы по-прежнему можете расширять интерфейсы, отказываясь от типа безопасности по цене.
trait One {
val receiveOne : PartialFunction[String,Unit] = {
case msg : String =>()
}
}
trait Two {
val receiveTwo : PartialFunction[Double, Unit] = {
case msg : Double =>()
}
}
trait Both extends One with Two {
val receive : PartialFunction[Any, Unit] = receiveOne orElse receiveTwo
}
Значение receive
в Both
признака сочетает в себе две частичные функции. Первый принимает только String
s, второй - только Double
s. У них есть один общий супертип: Any
. Поэтому расширенная версия должна использовать Any
в качестве аргумента и становится фактически нетипизированной. Недостаток находится в системе типа scala, которая поддерживает размножение типов с использованием ключевого слова with
, но не поддерживает типы объединения. Вы не можете определить Double or String
.
Типизированные участники теряют способность к простому расширению. Актеры сдвигают проверки типа на контравариантную позицию, и для ее расширения требуются типы профсоюзов. Вы можете видеть, как они работают в языке программирования ceylon.
Это не то, что нетипизированные и типизированные актеры имеют разные сферы применения. Все опрошенные функции могут быть выражены в терминах обоих. Выбор больше связан с методологией и удобством.
Ввод текста позволяет избежать ошибок перед тем, как перейти к модульному тестированию. Это будет стоить шаблона для объявлений вспомогательных протоколов.В приведенном выше примере вы должны объявить тип накидного явно:
trait Protocol
final case class First(message : String) extends Protocol
final case class Second(message : Double) extends Protocol
И вы теряете легко сочетание обратного вызова: нет orElse
метода для вас. Только рукописным
val receive : PartialFunction[Protocol, Unit] = {
case First(msg) => receiveOne(msg)
case Second(msg) => receiveTwo(msg)
}
И если вы хотели бы добавить немного новой функциональности с признаком Three
, то вы бы занят переписыванием, что шаблонный код.
Akka предлагает некоторые полезные предопределенные усовершенствования для актеров. Они добавляют новую функциональность либо с помощью mixin (например, receive pipeline), либо путем делегирования (например, reliable proxy). Шаблоны прокси используются в приложениях akka в значительной степени, и они изменяют протокол «на лету», добавляя к нему управляющую команду. Это не может быть сделано так легко с типизированными актерами. Поэтому вместо предопределенных утилит вам придется писать собственные реализации. А оставшиеся утилиты не ограничивались бы FSM.
Это зависит от вас, решите, улучшилось ли написание улучшенной работы. Никто не может дать точных рекомендаций без глубокого понимания вашего проекта.
Не могли бы вы связать это с контекстами, которые я упомянул? Я могу понять ваши примеры, но я не понимаю, почему это большая проблема. –
@CasperThuleHansen Ваш вопрос слишком широк, и я бы сказал, что этот вопрос обращается к нему разумно. – wheaties
Прошу прощения, но я не согласен. Я ищу несколько вариантов использования, где нетипизированная абстракция лучше, чем напечатанная. FSM один, есть ли еще? –