【问题标题】:Which design pattern is my Scala application using?我的 Scala 应用程序使用哪种设计模式?
【发布时间】:2018-01-10 03:44:04
【问题描述】:

我有一个 Scala 应用程序,它有一个实现某些功能的 trait 和一个扩展 traitclass

上面提到的类也有一个函数,它使用它的参数调用父 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()
    }
  }
}

【问题讨论】:

  • 继承模式?
  • and.... 为什么要在父特征上使用高阶函数?还有...为什么要在另一个函数中覆盖该函数?
  • @FelipeOliveiraGutierrez 它不是覆盖函数,它使用 lambda 参数进行调用,您可以像这样重写它,-withSparkContext (sc => { ... }) 这将起作用
  • 你是对的。我必须习惯这个 lambda...谢谢
  • 不客气,查看topic 看看它是如何工作的

标签: scala apache-spark design-patterns


【解决方案1】:

这里使用的是所谓的Loan Pattern(尽管可能有错误),以这种方式调用是因为它在您想要管理资源的生命周期时很有用(在你的情况是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 的事实有关。这可能没问题,但 贷款模式 的主要方面正是在管理资源时最小化错误面。您可能有兴趣执行以下操作(您想检查方法中的最后一行):

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 感兴趣,它围绕托管资源创建了一个非常漂亮且惯用的界面。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-03
    • 1970-01-01
    • 1970-01-01
    • 2014-04-23
    • 1970-01-01
    • 2011-10-30
    • 1970-01-01
    相关资源
    最近更新 更多