Scala中的功能链

Ham*_*amy 1 scala method-chaining

我似乎无法弄清楚如何将这些功能链接在一起,任何帮助或建议都将不胜感激。

// Generic approach to adding flags to a command string
trait UpdateCommandString {
  def update[T](option: Option[T], flagName: String)(implicit command: String): String = {
    if (option.isEmpty)
      command
    else if (option.get.isInstanceOf[Boolean]) {
      if (option.get.asInstanceOf[Boolean])
        s"$command $flagName"
      command
    } else
      s"$command $flagName ${option.get.asInstanceOf[String]}"        
  }
}

// One example of flags (the program I'm using has literally 50+ flags
// so there will be a number of case classes that group them into related
// sets)
case class Flags(cache: Option[String] = None,
  errorlog: Option[String] = None,
  accesslog: Option[String] = None,
  verbose: Option[Boolean] = Some(false),
  auth: Option[Boolean] = Some(false)) extends UpdateCommandString {

  def applyToCommand(implicit command: String): String = {
    // These seem to apply separately, but I want to chain 
    // them together!
    update(cache, "-cache")
    update(errorlog, "-error")
    update(accesslog, "-access")
    update(auth, "-do-auth")
  }
}

// An example of what I'm trying to do
// Given a base command string and a bunch of case classes to apply
// to that string, I'd like to be able to call applyToCommand and 
// get back the modified command string
var command = "run_system"
val f = Flags(Some("asdfasdf"), None, None, Some(true), Some(false))
command = f.applyToCommand(command)
Run Code Online (Sandbox Code Playgroud)

bma*_*her 5

我建议您彻底重新设计当前的方法。

类的每个成员都Flags应该是自己的案例类,并扩展一个公共Flag类。

因此,您可以定义函数以将不同的标志组合到一个配置中。最后,可以使用此配置来构建结果字符串。

abstract class Flag(name: String, parameter : Option[String])
case class Cache(parameter : Option[String]) extends Flag("-cache", parameter)
case class ErrorLog(parameter : Option[String]) extends Flag("-errorlog", parameter)
//...

type Config = List[Flag]

def applyToCommand(commandName : String, config : Config) = {
  def buildString(f:Flag) = 
    s" $f.name${f.parameter.map(" " ++ _).getOrElse("")}"

  val flagsString = config.map(buildString).mkString("")
  s"$commandName" ++ flagString
}

//Now you can it simply use it as I described above
val config = List(Cache(Some("asdf")), ErrorLog(None))
applyToCommand("run_system", config)
Run Code Online (Sandbox Code Playgroud)

这使您的代码更灵活,更易于重构。

最后,这里有一些建议,您可以如何修改此设计以更好地满足您的需求:

  • 如果需要对标志进行分组,可以将它们放在对象或单独的文件中。或者,如果您想基于组更改其行为,则可以增强类层次结构并添加中间层。

  • 您可以将参数从Flag下移到案例类,因此每个Flag都可以定义是否需要参数,如果需要,则定义多少个参数以及这些参数是否可选。

  • 您还可以buildString在案例类中实现,以便每个标志都可以决定如何自行格式化。

  • 如果要添加新的Flag,只需添加一个新类,就是这样,无需向不相关的类添加任何内容。