Учитывая, что реализуемый вами интерфейс Java, кажется, требует, чтобы реализация принимала произвольно много новых configInfo
s, я бы сказал, что самое честное - это оставить переменную, но инкапсулированную так, чтобы она могла только может быть изменено с помощью receiveConfigInfo
.
Так что, возможно, что-то вроде
object MyClass {
private[MyClass] Config {
private var underlying: Map[String, String] = Map.empty
override def get(key: String): Option[String] =
synchronized { underlying.get(key) }
override def toMap: Map[String, String] =
synchronized { underlying }
override def update(configInfo: String): Unit =
synchronized {
// I'm assuming that decode is somewhere statically accessible
// I'm also assuming that a function returning an `Either` won't throw non-fatal exceptions... if it can return a Left, a Right, or throw, then:
// Try { decode[...](configInfo) }.flatMap(_.left.map(msg => new RuntimeException(msg)).toTry)
val decoded =
decode[Map[String, String]](configInfo)
.left
.map(_ => new RuntimeException("decode failed")
.toTry
decoded.foreach { newConfig => underlying = newConfig }
decoded.recoverWith { _ =>
underlying = Map.empty
decoded
}
}
}
}
class MyClass extends Listener {
private val config = new MyClass.Config
override def receiveConfigInfo(configInfo: String): Unit = config.update(configInfo)
}
При таком решении конфигурация неизменна для всего в MyClass
, которое не вызывает update
(что, надо надеяться, достаточно очевидно по сравнению с присвоением var
.
Я сохраняю поведение сброса конфигурации, если появляется плохой configInfo
; может быть, имеет смысл оставить configInfo
без изменений в этом случае, что на практике еще более затруднит непреднамеренное изменение конфигурации, за исключением того, что клиент MyClass
вызывает receiveConfigInfo
с действительной конфигурацией.