控制抽象

根据正交设计的基本原则,如果设计出现重复的控制逻辑,可抽象出稳定的抽象;借助于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) }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 戏路如流水,从始至终,点滴不漏。一路百折千回,本性未变,终归大海。一步一戏,一转身一变脸,扑朔迷离。真心自然流露,...
    刘光聪阅读 6,112评论 3 13
  • 即使水墨丹青,何以绘出半妆佳人。 Scala是一门优雅而又复杂的程序设计语言,初学者很容易陷入细节而迷失方向。这也...
    刘光聪阅读 8,299评论 4 9
  • 读《快学Scala 》一书的摘要 Scala 运行于JVM之上,拥有海量类库和工具,兼顾函数式编程和面向对象。 在...
    abel_cao阅读 5,081评论 0 8
  • 桃花落,闲池阁,山盟虽在,锦书难托,莫,莫,莫! 「函数(Function)」是函数式编程的基本单元。本文将重点讨...
    刘光聪阅读 9,633评论 6 13
  • 《富爸爸穷爸爸》的作者罗伯特.清崎,他有2个“爸爸”,一个亲生父亲,是高学历的教育官员,另外一个是他好朋友的父亲,...
    沉睡中的狮子阅读 1,891评论 0 0

友情链接更多精彩内容