基于标志更新对象的功能方法

时间:2012-02-23 01:20:04

标签: scala functional-programming

假设您正在编写一个规范化字符串的类。该类有许多配置标志。例如:

   val makeLowerCase: Boolean = true
   val removeVowels: Boolean = false
   val dropFirstCharacter: Boolean = true

如果我正在编写可变代码,我会为normalize方法编写以下内容。

def normalize(string: String) = {
  var s = string

  if (makeLowerCase) {
    s = s.toLowerCase
  }

  if (removeVowels) {
    s = s.replaceAll("[aeiou]", "")
  }

  if (dropFirstCharacter) {
    s = s.drop(1)
  }

  s
}

是否有一种干净简单的方法来编写这些没有变异的方法?嵌套条件变得非常讨厌。我可以创建一个String=>String lambdas列表,根据配置过滤它,然后通过它折叠字符串,但我希望有更容易的东西。

2 个答案:

答案 0 :(得分:6)

最好的办法是定义自己的方法:

class ConditionalMapper[A](a: A) {
  def changeCheck(p: A => Boolean)(f: A => A) = if (p(a)) f(a) else a
  def changeIf(b: Boolean)(f: A => A) = if (b) f(a) else a
}
implicit def conditionally_change_anything[A](a: A) = new ConditionalMapper(a)

现在你把这些东西连在一起写下来:

class Normer(makeLC: Boolean, remVowel: Boolean, dropFirst: Boolean) {
  def normalize(s: String) = {
    s.changeIf(makeLC)   { _.toLowerCase }
     .changeIf(remVowel) { _.replaceAll("[aeiou]","") }
     .changeIf(dropFirst){ _.substring(1) }
  }
}

这给了你:

scala> val norm = new Normer(true,false,true)
norm: Normer = Normer@2098746b

scala> norm.normalize("The Quick Brown Fox Jumps Over The Lazy Dog")
res1: String = he quick brown fox jumps over the lazy dog

那就是说,可变解决方案也不错 - 只需将它保持在一个小块中就可以了。当你让可变性逃到野外时,这主要是一个问题。 (其中“野性”的意思是“在你的方法之外,或在任何方法之内,而不是少数几行”。)

答案 1 :(得分:4)

如果您使用scalaz |>运算符或在实用程序类中定义了类似运算符,则可以执行以下操作:

case class N(
  makeLowerCase: Boolean = true,
  removeVowels: Boolean = false,
  dropFirstCharacter: Boolean = true) {

  def normalize(string: String) = (
    string 
      |> (s => if (makeLowerCase) s.toLowerCase else s) 
      |> (s => if (removeVowels) s.replaceAll("[aeiou]", "") else s) 
      |> (s => if (dropFirstCharacter) s.drop(1) else s) 
  )

}

N(removeVowels=true).normalize("DDABCUI")
// res1: String = dbc