Ленивая загрузка некоторых параметров конфигурации, пытаясь придумать шаблон в Scala - PullRequest
3 голосов
/ 06 декабря 2008

Я хочу, чтобы мой клиентский код выглядел примерно так:

    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 ], мне нужно привести значения.

Ответы [ 2 ]

1 голос
/ 06 декабря 2008

Ничто не мешает вам просто сделать значения абстрактными. Вы не можете применить ленивость в супер-особенности, но это нормально, так как ленивая загрузка действительно является деталью реализации:

trait Config {
  val param1: String
  val param2: String
  val param3: Int
}

class MyConfig extends Config {
  lazy val param1 = readConfig().("p1")
  ...

  def readConfig(): Map[String, String] = ...
}

На стилистической ноте readConfig() должен быть объявлен и назван с парэнсом (а не без), поскольку это побочный метод. Синтаксис no-parens предназначен для обозначения чисто функциональных методов.

0 голосов
/ 06 декабря 2008

Если вы просто хотите упростить это, поля "param" могут быть методами ...

trait Config {
  def param1:String
  def param2:String
  def param3: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)

  def param1:String = data.get("p1").get.asInstanceOf[String]
  def param2:String = data.get("p2").get.asInstanceOf[String]
  def param3:Int = data.get("p3").get.asInstanceOf[Int]
}

Чтобы избавиться от кастинга, вы можете MyConfig обернуть ленивый внутренний класс, который лениво загружается на MyConfig.

class MyConfig(fileName:String) extends Config {
  private class NonLazyConfig(val p1:String, p2:String, p3:int) extends Config {
      def param1 = p1
      def param2 = p2
      def param1 = p3
  }
  lazy val inner:Config = readConfig

  // some dummy impl here, should read from a file
  protected def readConfig:Config = {
    return new NonLazyConfig("abc", "defgh", 43)
  }
  def param1:String = inner.param1
  def param2:String = inner.param2
  def param3:Int = inner.param3
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...