首页 > 解决方案 > Scala - 如何避免对象工厂的 if/else 条件

问题描述

我正在尝试解决以下问题。 问题

我尝试通过以下方式使用 Factory 解决问题,但仍然无法解决跨平台操作问题。而且代码看起来并不优雅。

执行

abstract class FileSystem(propFileURI: String) {
  def moveFile(): Unit
}

object FileSystem {

  private class HDFSystem(propFileURI: String) extends FileSystem(propFileURI) {
    override def moveFile(): Unit = {
      println(" HDFS  move file")
    }
  }

  private class S3System(propFileURI: String) extends FileSystem(propFileURI) {
    override def moveFile(): Unit = {
      println("S3 Move File ")
    }
  }

  def apply(propFileURI: String): Option[FileSystem] = {
    val properties: Properties = new Properties()

    val source = Source.fromFile( System.getProperty("user.dir")+"\\src\\main\\resources\\"+propFileURI).reader
    properties.load(source)
    val srcPath = properties.getProperty("srcPath")
    val destPath = properties.getProperty("destPath")

    if (destPath.contains("hdfs")){
       Some(new HDFSystem(propFileURI))
    }
    if (srcPath.contains("s3") && destPath.contains("s3")){
      Some(new S3System(propFileURI))
    }else{
       None
    }

  }

  def main(args: Array[String]): Unit = {
    val obj = FileSystem("test.properties")
    obj match {
      case Some(test) => test.moveFile()
      case None => println("None returned")
    }
  }
}

问题:

  1. 当前moveFile仅执行句柄s3->s3hdfs->hdfs. 如何为local->hdfs 和实现相同的方法local->s3

  2. 如何移动HDFSystemS3System分离文件?

  3. if/else方法上如何避免apply

标签: scaladesign-patternsscalability

解决方案


您可以替换if-else为模式匹配。但是,这不仅仅是if-else陈述,对吧?所以可以写成下面这样:


sealed abstract class FileSystem(propFileURI: String) {
  def moveFile(): Unit
}

case class HDFSystem(propFileURI: String) extends FileSystem(propFileURI) {
  override def moveFile(): Unit =
    println(" HDFS  move file")
}

case class S3System(propFileURI: String) extends FileSystem(propFileURI) {
  override def moveFile(): Unit =
    println("S3 Move File ")
}
case class MoveFile(hdfs: Option[HDFSystem] = None, s3: Option[S3System] = None)

object FileSystem {

  def apply(propFileURI: String): MoveFile = {
    val properties: Properties = new Properties()
    val source = Source.fromFile(System.getProperty("user.dir") + "\\src\\main\\resources\\" + propFileURI).reader
    properties.load(source)

    val srcPath = Option(properties.getProperty("srcPath")).fold(false)(_.contains("hdfs"))
    val destPath = Option(properties.getProperty("destPath")).fold(false)(_.contains("s3"))

    (destPath, srcPath) match {
      case (true, true) =>
        MoveFile(
          hdfs = Option(HDFSystem(propFileURI)),
          s3 = Option(S3System(propFileURI))
        )
      case (false, true) =>
        MoveFile(s3 = Option(S3System(propFileURI)))
      case (true, false) =>
        MoveFile(hdfs = Option(HDFSystem(propFileURI)))
      case _ =>
        MoveFile()
    }
  }
}

object TestObj {

  def main(args: Array[String]): Unit = {
    val obj = FileSystem("test.properties")
    (obj.hdfs, obj.s3) match {
      case (Some(hdfs), _) => hdfs.moveFile()
      case (_, Some(s3)) => s3.moveFile()
      case (_, _) => println("None returned")
    }
  }
}

老实说,我不喜欢上面的实现,并为下面的用例做了一些修改。您可以将它们用作没有MoveFile包装器的 ADT:


def testMethod(fs: FileSystem): Unit = {
  fs.moveFile()
}

def main(args: Array[String]): Unit = {
// You can have a logic here for which way to go
  val obj = S3System("test.properties")
  testMethod(obj)
  val obj1 = HDFSystem("test.properties")
  testMethod(obj1)
}

在这种情况下,您可以完全移除FileSystem对象。如果你想有一些路径检查器,你可以在每个sub-types. HdfsSystem并且S3Sytem应该实现moveFile方法


推荐阅读