将可变java类转换为不可变scala类

将可变java类转换为不可变scala类,scala,immutability,Scala,Immutability,我有一个类似这样的类 class OutputFile(name: String, index: Int = 0){ val localFile = File.createTempFile(name, ".gz") localFile.deleteOnExit() val localFileOut =new FileOutputStream(localFile) private[this] var bytesWritted: Int = 0 def write(line: B

我有一个类似这样的类

class OutputFile(name: String, index: Int = 0){
  val localFile = File.createTempFile(name, ".gz")
  localFile.deleteOnExit()
  val localFileOut =new FileOutputStream(localFile)
  private[this] var bytesWritted: Int = 0
  def write(line: Bytes): OutputFile = {
    if(bytesWritten > SOMESIZE) flush //this function uploads the file to a different location and closes the localfile and localFileOut
    try{
      writeLine(line) //this writes the line to the localfile
      this
    }catch{
      //If the file had been closed by flush create a new object
      case IOException => 
        val outFile = new OutputFile(name, index+1)
        outfile.write(line)
        outfile
    }
    //Other functions like flush and writeLine
  }
但是现在我不能将此对象与不可变对象一起使用。来自java背景的我很难将这个类转换为不可变的样式。在java代码中,我们可以对输出流使用一个全局变量,并在需要时对其进行更改


有没有更好的方法,我肯定没有实现这样的场景。

要使
OutputFile
的工作流不可变,每个调用都必须返回一个新的不可变实例,而不仅仅是交换outfile的调用:

object OutputFile {
  def apply(name: String): OutputFile = {
    new OutputFile(name, newStream(name), 0)
  }

  private def newStream(name: String): FileOutputStream = {
    val localFile = File.createTempFile(name, ".gz")
    localFile.deleteOnExit()
    new FileOutputStream(localFile)
  }
}

class OutputFile(name: String, stream: FileOutputStream, bytesWritten: Int) {

  val THRESHOLD = 1000000

  def write(line: Bytes): OutputFile = write(line, 1)

  private def write(line: Bytes, attempt: Int): OutputFile = {
    try {
      val written = writeLine(line) //this writes the line to the localfile
      if (written > THRESHOLD) {
        flush
        new OutputFile(name, OutputFile.newStream(name), 0)
      } else new OutputFile(name, stream, written)
    } catch {
      case x: IOException =>
        if (attempt > 3) throw x
        else write(line, attempt + 1)
    }
  }

  // returns bytesWritten + length of line
  private def writeLine(line: Bytes): Int = ???

  // uploads file, closes and deletes it
  private def flush: Unit = ???
}
我添加了一个伴生对象
OutputFile
,这样实际的构造函数就是新的不可变实例的构造函数,并抽象出新流的打开

每次调用write都会创建一个新的
OutputFile
,并跟踪已写入当前文件的字节数。一旦达到
阈值
,将刷新文件并返回一个具有新流的新实例。
IOException
不再负责触发新文件(当我们知道已刷新时才触发),而是重试,最多尝试3次


最后一点警告:这个类本质上仍然是有状态的,因为它确实处理文件I/O。虽然它试图假装没有状态,但它假设一个实例上永远不会调用write两次。

这太棒了!最后一个问题。从我的(糟糕的)实现尝试中,我了解到write只能调用一次。我们能不能改变这种情况,允许多次写入?如果不能,还有什么更好?在这个类的用户上有一个可变的outputstream或可变的OutputFile对象。问题是这个类的存在纯粹是因为它的副作用,这总是很难使它不可变。我认为你最好的方案就是接受它;s作为一种副作用性质,并封装其状态性,而不是尝试某种泄漏的不可变版本。如果您真的想进入函数I/O,我建议您阅读IO Monad