Scala - Шаблон фабричного объекта навесного оборудования - PullRequest
1 голос
/ 18 апреля 2020

Я пытаюсь реализовать шаблон проектирования фабрики объектов в scala. Однако я не могу предпринять, как вернуть объект на основе условия.

Я попытался вернуть Option, однако он не работает должным образом.

import java.io.File
import java.util.Properties

import scala.io.Source

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

object FileSystem {

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

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

  // How to handle this??
  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")

    var Obj = None:Option[FileSystem]

    if (destPath.contains("hdfs")){
      Obj = Option(new HDFSystem())
    }
    if (srcPath.contains("s3") && destPath.contains("s3")){
     Obj = Option(new S3System())
    }
    Obj
  }

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

  }
}

Как обращаться с методом Apply на основе условия, которое я упомянул? Мне действительно нужно вернуть option?

Ответы [ 2 ]

2 голосов
/ 18 апреля 2020

Существуют способы очистить вашу реализацию, например, можно избежать использования var

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

однако, насколько я понимаю, основной вопрос заключается в

Нужно ли мне возвращать Option?

Это дизайнерское решение с компромиссами и без четкого ответа. Спросите себя, как должна реагировать система, если в файле .properties отсутствует соответствующий ключ конфигурации:

  • Можем ли мы создать значимый объект по умолчанию FileSystem? В этом случае нет необходимости в Option, просто верните значение по умолчанию и продолжите обработку.
  • Если мы не можем создать значимое значение по умолчанию, есть ли смысл продолжать? Должна ли система взломать sh? В этом случае мы можем выбросить.
  • Если система может продолжать работать, несмотря на то, что не может построить FileSystem, то мы можем смоделировать эту информацию как Option или Either et c., Возможно зарегистрируйте событие и продолжите обработку.

Это только некоторые соображения, которые необходимо учитывать. Лично я обнаружил, что неправильно настроенную систему трудно восстановить.

1 голос
/ 18 апреля 2020

Option s не Java s @nullable s. Вы сопоставляете шаблон на Some, если присутствует значение:

    val obj = FileSystem("test.properties") // Option[FileSystem]
    obj match {
      case Some(test) => test.moveFile("test.properties")
      case None       =>
    }

Также в Scala почти все является выражением, поэтому if-else, блоки, циклы и функции возвращают свое последнее значение как значение всех , Также мы должны принимать во внимание ошибки ввода-вывода, поэтому Try может быть лучше, чем Option:

  def apply(propFileURI: String): Try[FileSystem] =
    Try {
      // reading properties could fail
      val p = new Properties()
      val source = Source.fromFile( System.getProperty("user.dir")+"\\src\\main\\resources\\"+propFileURI).reader
      p.load(source)
      p
    }.flatMap { properties =>
      // reading from properties could fail
      val srcPath = properties.getProperty("srcPath")
      val destPath = properties.getProperty("destPath")

      if (destPath.contains("hdfs")) Success(new HDFSystem())
      else if (srcPath.contains("s3") && destPath.contains("s3")) Success(new S3System())
      else Failure(new Exception("Unable to recognize filesystem"))
    }

  def main(args: Array[String]): Unit =
    FileSystem("test.properties") match {
      case Success(fileSystem) => fileSystem.moveFile("test.properties")
      case Failure(error)      => error.printStackTrace()
    }

Мы можем в любой момент преобразовать Try в Option с .toOption и pattern- совпадать на нем. Но таким образом у нас нет информации об ошибке. Мы также можем создать тип FileSystemError для хранения информации об ошибках и вернуть Either[FileSystemError, FileSystem] вместо Try. Наконец, мы могли бы просто выбросить Exception, но таким образом мы возвращаемся к Java -подобным практикам, которые не говорят нам, что ошибка может произойти, и это удивляет нас во время выполнения.

Что я, несомненно, хотел бы do - переименовать apply - обычно мы ожидаем, что объект apply всегда будет возвращать успех, поэтому, если это невозможно, и мы используем какой-то умный конструктор, мы должны дать ему другое имя. Например, здесь мы могли бы назвать его

def resolveFor(propFileURI: String): Either[FileSystemError, FileSystem] = ...

, чтобы каждый, кто использовал его, знал, какое поведение ожидать только от подписи.

...