声明和初始化实例/类变量的首选方式

时间:2014-06-05 01:48:57

标签: scala optional

在以下来自类或对象的片段中(我假设两者的处理方式相似),

  private var consumer : Consumer = _
  def getConsumer(channel : Channel)  = if (consumer != null) {
    consumer } 
  else {
    // build it
  }

我不相信在所有情况下我们都会盲目地抛出一个选项:

  private var consumer : Option[Consumer] = None
  def getConsumer(channel : Channel)  = consumer.getOrElse(
            // build it
            consumer = Some(/* built val */)
  }

是的,以上情况很有可能,但我的预感是有替代方案。见解表示赞赏。

编辑消费者对象直接发送给第三方API;因此,这里不需要更改/装饰需要签名更改。

以下是一个例子:

channel.basicConsume(queue, true, getConsumer(channel))

OR

// assuming consumer were already constructed with a Channel instance in the constructor
channel.basicConsume(queue, true, consumer)

2 个答案:

答案 0 :(得分:3)

理想情况下,您希望在构造对象时初始化所有字段。 lazy val可以选择暂停初始化,直到需要使用该值。 在您的用例中,我建议将通道传递给构造函数并使用它,如下所示:

case class WithChannel(channel: Channel){
  lazy val consumer = {create consumer, you can use channel here}

  channel.basicConsume(queue, true, consumer)
}

如果在构造对象的其余部分时无法始终拥有通道,那么使用类来表示未初始化的情况可能很有用。

case class Uninitialised(someArg: Any){
  def withChannel(channel: Channel) = Initialised(someArg, channel)
}

case class Initialised(someArg: Any, channel: Channel){
  lazy val consumer = { some means of creating the consumer }

  channel.basicConsume(queue, true, consumer)
}

val uninit = Uninitialised("Bob")
val init = uninit.withChannel(channel)

这样做的好处是有null s,没有Option s,对象的状态是由它的类型描述的,而不是它的成员。


您是使用class代替case class

吗?
class Initialised(someArg:Any, val channel: Channel) 

注意val之前的channel。这使channel成为类的一个字段,而不仅仅是构造函数的一个参数。如果您想在对象的初始化之外使用它,例如,这是必要的。在方法和构造惰性vals。 case class es的参数隐含val

答案 1 :(得分:1)

您尝试重新创建的模式称为Memoization。

val getConsumer = {
  val cache = collection.mutable.Map.empty[Channel, Consumer]
  (channel : Channel) => cache.getOrElseUpdate(channel, Consumer(channel))
}

值得一提的是,上面假设你在构造函数中构建Consumer。否则,您可以使用您想要的任何功能而不是Consumer(channel)

这个模式由很多Scala库包装,所以你可以依赖它。例如,Scalaz。