我似乎无法弄清楚如何将这些功能链接在一起,任何帮助或建议都将受到赞赏。
// 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)
答案 0 :(得分:4)
我建议您完全重新设计当前的方法。
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)
这使您的代码更灵活,更容易重构。
最后,我们建议您如何修改此设计以更好地满足您的需求:
如果需要对标志进行分组,可以将它们放在对象或单独的文件中。或者,如果您想根据组更改其行为,可以增强类层次结构并添加中间层。
您可以将参数从Flag
向下移动到案例类,这样每个Flag都可以定义它是否需要参数,如果是,是多少以及是否可选。
您还可以在案例类中实现buildString
,以便每个标志可以决定如何自行格式化。
如果你想添加新的Flags,你只需添加一个新的类就可以了,不需要在不相关的类中添加任何内容。
答案 1 :(得分:0)
正如@bmaderbacher所解释的那样,我认为你应该将不同的案例类中的不同标志分开。
但要回答您的问题,您应该修改applyToCommand
:
def applyToCommand(implicit command: String): String = {
var s = update(cache, "-cache")(command)
s = update(errorlog, "-error")(s)
s = update(accesslog, "-access")(s)
s = update(auth, "-do-auth")(s)
s
}
此时应该很清楚,您没有为Flag
课做出正确的选择。
我会做那样的事情:
trait Flag {
def toString: String
}
case class Command(value: String) {
def add(flag: Flag) = Command(value + ' ' + flag.toString)
def +(flag: Flag) = add(flag)
}
case class Cache(size: Int) extends Flag {
def toString = s"--cache $size"
}
case object Auth extends Flag {
def toString = "--auth"
}
现在您可以执行以下操作:
val command = Command("run") + Cache(500) + Auth