scala学习:控制抽象

Java基础

浏览数:105

2019-11-1

AD:资源代下载服务

控制抽象

减少重复代码

重复代码

这是一开始最可能写出来的代码,代码很简单,就是文件名的过滤功能。

object FileMatcher {

  private def files = new File(".").listFiles()

  def filesEnding(query: String): Array[File] = {

    for (file <- files; if file.getName.endsWith(query))
      yield file
  }

  def FilesContaining(query: String): Array[File] = {
    for (file <- files; if file.getName.contains(query))
      yield file
  }

  def FilesRegexing(query:String): Unit ={
    for (file <- files; if file.getName.matches(query))
      yield file
  }
}

将逻辑抽象出来

定义个filesMatching方法,将逻辑抽象,现在看着就舒服多了。

但还不够完美。

object FileMatcher {

  private def files = new File(".").listFiles()

  def filesEnding(query: String): Array[File] = {

    filesMatching(query,_.endsWith(_))
  }

  def FilesContaining(query: String): Array[File] = {
    filesMatching(query,_.contains(_))
  }

  def FilesRegexing(query: String): Unit = {
    filesMatching(query,_.matches(_))
  }
  
  def filesMatching(query: String, matcher: (String, String) => Boolean): Array[File] = {

    for (file <- files; if matcher(file.getName, query))
      yield file
  }
}

去掉不必要参数

在逻辑方法中,去掉参数,这样就更清爽了。

object FileMatcher {

  private def files = new File(".").listFiles()

  def filesEnding(query: String): Array[File] = {

    filesMatching(_.endsWith(query))
  }

  def FilesContaining(query: String): Array[File] = {
    filesMatching(_.contains(query))
  }

  def FilesRegexing(query: String): Unit = {
    filesMatching(_.matches(query))
  }

  def filesMatching(matcher: String => Boolean): Array[File] = {

    for (file <- files; if matcher(file.getName))
      yield file
  }
}

借贷模式

假设你需要打开一个文件,你最后总是需要考虑关闭资源。有没有什么办法,让我们不会忽略这个动作。(不使用try())

object printWriterTest {

  def withPrintWriter(file: File)(op: PrintWriter => Unit): Unit = {
    val writer = new PrintWriter(file)
    try {
      op(writer)
    } finally {
      writer.close()
    }
  }
}

接下来你可以这么使用这个函数

withPrintWriter(new File("test.txt"))(writer => writer.println("test"))

传名参数

传名参数比起简单的参数传输,不一样的地方在于。

简单的参数传输会先计算这个表达式,而传名参数则在需要它的时候才会去计算。

以下示例代码,只有boolAssert(5/0==0) 才会抛出错误。

object ByNameAssertTest {

  def main(args: Array[String]): Unit = {
    byNameAssert(5 / 0 == 0)
    boolAssert(5 / 0 == 0)
  }

  var assertEnable = false


  def byNameAssert(predict: => Boolean): Unit = {

    if (assertEnable && !predict) {
      throw new AssertionError()
    }
  }

  def boolAssert(predict: Boolean): Unit = {
    if (assertEnable && !predict) {
      throw new AssertionError()
    }
  }

}

作者:小鸡