3

我希望我的客户端代码看起来像这样:

    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 ],所以我需要转换值。

4

2 回答 2

1

没有什么可以阻止您将值抽象化。您不能在超级特征中强制执行惰性,但这没关系,因为无论如何延迟加载实际上是一个实现细节:

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()应该用括号(而不是不带)声明和调用,因为它是一种副作用方法。无括号语法旨在表示纯函数方法。

于 2008-12-06T06:03:58.427 回答
0

如果您只是想简化它,“参数”字段可能是方法......

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
}
于 2008-12-06T03:56:55.953 回答