在以下来自类或对象的片段中(我假设两者的处理方式相似),
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)
答案 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。