我的Scala应用程序使用哪种设计模式?

时间:2018-01-09 13:13:16

标签: scala apache-spark design-patterns

我有一个Scala应用程序,其trait实现了一些功能,而class扩展了trait

上面提到的类还有一个函数,它使用它的参数调用父特征中定义的函数。

我在使用Scala的Spark + Kafka实现中观察到了这一点。我猜这是某种设计模式,但我不知道哪一个。是蛋糕模式吗?依赖注入模式?或其他什么?

以下是我所指的代码:

trait SparkApplication {
  def sparkConfig: Map[String, String]
  def withSparkContext(f: SparkContext => Unit): Unit = {
    val conf = new SparkConf()
    sparkConfig.foreach { case (k, v) => conf.setIfMissing(k, v) }
    val sc = new SparkContext(conf)
    f(sc)
  }
}

trait SparkStreamingApplication extends SparkApplication {
  def withSparkStreamingContext(f: (SparkContext, StreamingContext) => Unit): Unit = {
    withSparkContext { sc =>
      val ssc = new StreamingContext(sc, Seconds(streamingBatchDuration.toSeconds))
      ssc.checkpoint(streamingCheckpointDir)
      f(sc, ssc)
      ssc.start()
      ssc.awaitTermination()
    }
  }
}

1 个答案:

答案 0 :(得分:2)

这里使用的是什么(虽然可能有错误)是所谓的贷款模式,以这种方式调用,因为它在您想要管理生命周期时非常有用资源(在您的情况下为SparkContext),同时允许用户定义资源的使用方式。

这方面的一个典型示例是文件:您想要打开文件,阅读它的内容,然后在完成后立即将其关闭,而不会让用户犯错误而忘记关闭资源。您可以按如下方式实现:

import scala.io.Source

// Read a file at `path` and allow to pass a function that iterates over lines
def consume[A](path: String)(f: Iterator[String] => A): A = {
  val source = Source.fromFile(path)
  try {
    f(source.getLines)
  } finally {
    source.close()
  }
}

然后你按照以下方式使用它(在示例中,只打印与其数字配对的所有行):

consume("/path/to/some/file")(_.zipWithIndex.foreach(println))

正如您可能已经注意到,您的代码中有一些非常接近的事情,唯一的区别是您管理的生命周期的资源是SparkContext

关于我最初提到的可能错误,它认为你借用一个你永远不会关闭的SparkContext这个事实。这可能没问题,但 Loan Pattern 的主要方面正是在管理资源时最小化错误表面的方面。你可能有兴趣做以下事情(你想检查方法的最后一行):

def withSparkContext(f: SparkContext => Unit): Unit = {
  val conf = new SparkConf()
  sparkConfig.foreach { case (k, v) => conf.setIfMissing(k, v) }
  val sc = new SparkContext(conf)
  f(sc)
  sc.stop() // shutdown the context after the user is done
}

您可以阅读有关此模式的更多信息here

作为旁注,您可能会对this project感兴趣,它会在托管资源周围创建一个非常好的和惯用的界面。