根据正交设计的基本原则,如果设计出现重复的控制逻辑,可抽象出稳定的抽象;借助于Scala
强大的可扩展能力,可以将「小括号」神奇地转换为「大括号」,让用户代码感觉是一种新的控制结构。
本文通过一个简单的例子,通过若干迭代,遵循正交设计的基本原则,灵活地应用重构,逐渐改进设计,以供参考。
需求1:搜索目录下扩展名为
.scala
的所有文件
快速实现
object FileMatchers {
def ends(file: File, ext: String) = {
for (file <- file.listFiles if file.getName.endsWith(ext))
yield filelist
}
}
需求2:搜索目录下名字包含
Test
的所有文件
重复
object FileMatcher {
def ends(file: File, ext: String) = {
for (file <- file.listFiles if file.getName.endsWith(ext))
yield file
}
def contains(file: File, query: String) = {
for (file <- file.listFiles if file.getName.contains(query))
yield file
}
}
需求3:搜索目录下名字正则匹配特定模式的所有文件
再现重复
object FileMatcher {
def ends(file: File, ext: String) = {
for (file <- file.listFiles if file.getName.endsWith(ext))
yield file
}
def contains(file: File, query: String) = {
for (file <- file.listFiles if file.getName.contains(query))
yield file
}
def matches(file: File, regex: String) = {
for (file <- file.listFiles if file.getName.matches(regex))
yield file
}
}
提取抽象
消除消除上述实现的重复,最重要的是提取公共的关注点: Matcher: (String, String) => Boolean
。
object FileMatcher {
private def list(file: File, query: String,
matcher: (String, String) => Boolean) = {
for (file <- file.listFiles if matcher(file.getName, query))
yield file
}
def ends(file: File, ext: String) =
list(file, ext, (fileName, ext) => fileName.endsWith(ext))
def contains(file: File, query: String) =
list(file, query, (fileName, query) => fileName.contains(query))
def matches(file: File, regex: String) =
list(file, regex, (fileName, regex) => fileName.matches(regex))
}
类型推演
借助于Scala
强大的类型推演能力,可以得到更为简洁的函数字面值。
object FileMatcher {
private def list(file: File, query: String,
matcher: (String, String) => Boolean) = {
for (file <- file.listFiles if matcher(file.getName, query))
yield file
}
def ends(file: File, ext: String) =
list(file, ext, _.endsWith(_))
def contains(file: File, query: String) =
list(file, query, _.contains(_))
def matches(file: File, regex: String) =
list(file, regex, _.matches(_))
}
类型别名
list
的参数由于类型修饰,显得有点过长而影响阅读;可以通过「类型别名」的机制缩短函数的类型修饰符,以便改善表达力。
object FileMatcher {
private type Matcher = (String, String) => Boolean
private def list(file: File, query: String, matcher: Matcher) = {
for (file <- file.listFiles if matcher(file.getName, query))
yield file
}
def ends(file: File, ext: String) =
list(file, ext, _.endsWith(_))
def contains(file: File, query: String) =
list(file, query, _.contains(_))
def matches(file: File, regex: String) =
list(file, regex, _.matches(_))
}
简化参数
简化参数传递,消除不必要的冗余,是简单设计基本原则之一。
object FileMatcher {
private type Matcher = String => Boolean
private def list(file: File, matcher: Matcher) = {
for (file <- file.listFiles if matcher(file.getName))
yield file
}
def ends(file: File, ext: String) =
list(file, _.endsWith(ext))
def contains(file: File, query: String) =
list(file, _.contains(query))
def matches(file: File, regex: String) =
list(file, _.matches(regex))
}
替换for comprehension
可以通过定制「高阶函数」替代语法较为复杂的「for comprehension」,以便改善表达力。
object FileMatcher {
private type Matcher = String => Boolean
private def list(file: File, matcher: Matcher) =
file.listFiles.filter(f => matcher(f.getName))
def ends(file: File, ext: String) =
list(file, _.endsWith(ext))
def contains(file: File, query: String) =
list(file, _.contains(query))
def matches(file: File, regex: String) =
list(file, _.matches(regex))
}
柯里化
应用「柯里化」,漂亮的「大括号」终于登上了舞台。
object FileMatcher {
private type Matcher = String => Boolean
def list(file: File)(matcher: Matcher) =
file.listFiles.filter(f => matcher(f.getName))
def ends(file: File, ext: String) =
list(file) { _.endsWith(ext) }
def contains(file: File, query: String) =
list(file) { _.contains(query) }
def matches(file: File, regex: String) =
list(file) { _.matches(regex) }
}
网友评论