Scala 设置不可变字段以供以后使用

Scala 设置不可变字段以供以后使用,scala,Scala,我的情况是,我需要在一个单例对象中设置一个特定的字段,以便以后可以使用它 def register(importantField: String): Unit = { Factory.setField(importantField) } 其中工厂为: object Factory { var field: Option[String] = None def setField(importantField: String): Unit = { field = Option(

我的情况是,我需要在一个单例对象中设置一个特定的字段,以便以后可以使用它

def register(importantField: String): Unit = {
  Factory.setField(importantField)
}
其中
工厂
为:

object Factory {
  var field: Option[String] = None

  def setField(importantField: String): Unit = {
    field = Option(importantField)
  }

  def functionThatWillBeCalledLater: Unit = {
    // do something with member "field"
  }
}

但是我真的想避免使用
var
。有什么惯用的方法可以做到这一点吗?

单例对象必须是线程安全的-因为对象是静态的,不能保证只有一个线程会访问它,所以您不使用
var
的调用是完全合理的。所有的
val
s都是最终的,并且保证是线程安全的,但是我们不能对
var
s说同样的话(而且,如果我们说的是惯用的,可变状态通常是不受欢迎的)

您可以为私有var实现自己的getter和setter(使用适当的同步),或者为此使用
scala.concurrent.Promise
——一个
Promise
只能完成一次,并且保证是线程安全的

导入scala.concurrent.Promise
对象工厂{
private val_字段:Promise[String]=Promise()
//下面的符号允许您通过`Factory.field=“a”进行设置`
def field=(值:字符串):布尔=_field.trySuccess(值)
def field:Option[String]=\u field.future.value.flatMap(\u.toOption)
}

也就是说,处理具有可变基线条件的工厂的最惯用的Scala方法是创建一个将所有变量设置为所需值的工厂。一个
对象本质上只是一个
val
,因此,你可以用
工厂的所有参数来实例化
工厂,一旦它们可用,你就可以在任何地方使用它们。

不要这样做。全球工厂,除了充满活力和破坏引用透明度之外,也是单元测试的噩梦。您应该真正考虑以某种方式设计代码,在这种方式中,您可以将所有“重要字段”保留在需要它们的地方

诀窍在于,不是像

    class Foo {
       def doFoo() = Factory.bar
    }
    Factory.register(param)
    new Foo().doFoo()
你得写信

   class Foo { 
      def doFoo(factory: Factory) = factory.bar
   }
   new Foo().doFoo(new Factory(param)
或许

   class Foo(factory: Factory) {
      def doFoo() = factory.bar
   }
   new Foo(new Factory(param)).doFoo

相比之下,把所有的东西都扔到一个全局状态对象中,然后从任何地方访问它,这似乎有点乏味。。。但这只是因为该函数在任何地方的所有使用都始终使用相同的参数值(在这种情况下,最好首先是一个常量),或者(也许更重要的是)直到您开始考虑编写单元测试来测试使用
工厂的地方。您不能模拟对象。。。那么,你会怎么做?

将状态置于
对象中不是一个好的做法。单例模式可能是。。。最好将
对象
视为Scala中的模块,而不是单一Java版本。我建议您重新考虑将全局
对象作为全局变量的想法。