Я хочу, чтобы мой клиентский код выглядел примерно так:
val config:Config = new MyConfig("c:/etc/myConfig.txt")
println(config.param1)
println(config.param2)
println(config.param3)
Что означает, что:
- Интерфейс Config определяет поля конфигурации
- MyConfig - это реализация Config - вся необходимая проводка - это создание нужной реализации
- Данные загружаются лениво - это должно происходить при первом обращении к полю (в данном случае config.param1)
Итак, я хочу, чтобы клиентский код был дружественным, с поддержкой взаимозаменяемых реализаций, со статически типизированными полями, скрывающими отложенную загрузку. Я также хочу, чтобы он был максимально простым для создания альтернативных реализаций, поэтому Config должен вас чем-то направлять.
Я не удовлетворен тем, что я до сих пор придумал:
trait Config {
lazy val param1:String = resolveParam1
lazy val param2:String = resolveParam2
lazy val param3:Int = resolveParam3
protected def resolveParam1:String
protected def resolveParam2:String
protected def resolveParam3:Int
}
class MyConfig(fileName:String) extends Config {
lazy val data:Map[String, Any] = readConfig
// some dummy impl here, should read from a file
protected def readConfig:Map[String,Any] = Map[String, Any]("p1" -> "abc", "p2" -> "defgh", "p3" -> 43)
protected def resolveParam1:String = data.get("p1").get.asInstanceOf[String]
protected def resolveParam2:String = data.get("p2").get.asInstanceOf[String]
protected def resolveParam3:Int = data.get("p3").get.asInstanceOf[Int]
}
Я уверен, что есть лучшие решения, в этом вы можете помочь:)
Одна вещь, которая мне особенно не нравится здесь, это то, что MyConfig определяет промежуточный контейнер с некоторыми произвольными ключами, и, поскольку это Map [String, Any ], мне нужно привести значения.