Это не обязательно вопрос Scala, это вопрос дизайна, связанный с избеганием изменчивого состояния, функционального мышления и тому подобного. Просто так получается, что я использую Scala.
Учитывая этот набор требований:
Входные данные поступают из практически бесконечного потока случайных чисел от 1 до 10
Окончательный результат - либо УСПЕШНЫЙ, либо СБОЙ
Может быть несколько объектов, «слушающих» поток в любое конкретное время, и они могут начать слушать в разное время, поэтому у всех них может быть разное понятие «первого» числа; следовательно, слушатели потока должны быть отделены от самого потока.
псевдокод:
if (first number == 1) SUCCEED
else if (first number >= 9) FAIL
else {
first = first number
rest = rest of stream
for each (n in rest) {
if (n == 1) FAIL
else if (n == first) SUCCEED
else continue
}
}
Вот возможная изменчивая реализация:
sealed trait Result
case object Fail extends Result
case object Succeed extends Result
case object NoResult extends Result
class StreamListener {
private var target: Option[Int] = None
def evaluate(n: Int): Result = target match {
case None =>
if (n == 1) Succeed
else if (n >= 9) Fail
else {
target = Some(n)
NoResult
}
case Some(t) =>
if (n == t) Succeed
else if (n == 1) Fail
else NoResult
}
}
Это будет работать, но пахнет для меня. StreamListener.evaluate не является ссылочно прозрачным. И использование токена NoResult просто не кажется правильным. Он имеет преимущество в том, что он понятен и прост в использовании / коде. Кроме того, должно быть функциональное решение этого права?
Я предложил 2 других возможных варианта:
Оценив, верните (возможно, новый) StreamListener, но это означает, что мне придется сделать Result подтипом StreamListener, который кажется неправильным.
Позволяя оценке принимать Stream [Int] в качестве параметра и позволяя StreamListener отвечать за потребление столько Stream, сколько необходимо для определения сбоя или успеха. Проблема, которую я вижу с этим подходом, состоит в том, что класс, который регистрирует слушателей, должен запрашивать каждого слушателя после того, как каждый номер сгенерирован, и предпринимать соответствующие действия сразу после сбоя или успеха. При таком подходе я не вижу, как это могло бы произойти, поскольку каждый слушатель принудительно оценивает поток, пока он не завершит оценку. Здесь нет концепции генерации одного числа.
Есть ли какая-то стандартная идиома Scala / FP, которую я здесь пропускаю?