2014-06-05 77 views
2

在从任一类或对象(I假定两者的治疗将是相似的)下面的代码片断,:优选的方式声明和初始化实例/类变量

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) 
+3

这看起来像你正在试图重新创建'lazy val'功能。也许看看这是怎么完成的。 – ggovan

+0

Thx为小费。我现在正在研究懒惰的val(并且你是对的 - 我不是很熟悉它们) – javadba

+0

@ggovan我们如何处理懒惰val的Channel参数? – javadba

回答

1

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

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

值得一提的是,以上您在它的构造打造Consumer推定去。否则,你可以使用任何你想要的功能,而不是Consumer(channel)

这个模式被很多Scala库包装,所以你可以只依靠一个。例如,斯卡拉兹。

+0

您的解决方案需要新的集合。为什么这比单纯的选择更可取?私有var消费者:选项[消费者] =无。我正在思考一种模式:创建一个更简单的结构就足够了的新集合似乎有点沉重。 – javadba

+0

也许您的解决方案假设存在多个(渠道,消费者)配对?在那种情况下是的。但是,对于单个条目 - 这里就是这种情况 - 您要做什么? – javadba

+1

@javadba那么,你的设计有一些严重的问题。它要么是一个消费者,要么使用'lazy val',要么使用memoized函数,这会缓存多个消费者,或者根本没有缓存。您的基于“Option”的解决方案是一个潜在的错误。使用某个通道调用'getConsumer'会创建一些'Consumer',如果之前设置了None,但它将返回一个'Consumer',否则可能会创建一个完全不同的'Cache'。这是一些搞砸的行为。你应该重新考虑你的设计。 –

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,NO Option s时,对象的状态由它的类型,而不是它的承包商,客人说明。


是你使用class代替case class

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

注意valchannel前。这使得channel成为类的一个字段,而不仅仅是构造函数的参数。如果你想在对象的初始化之外使用它,这是必需的,例如,在方法和构建懒惰的vals。参数case classES隐含地为val

+0

那么你明确地将一大堆思想和努力放在这里。目前还不清楚这是如何直接帮助特定用例的:我需要一个消费者对象。你展示的课程有种跳舞的感觉。例如WithChannel:这不是消费者的直接替代品。是吗?请考虑调用someMEthodNeedingConsumer(consumer)。然后展示你的建筑如何符合这个签名。 – javadba

+0

@javadba您能否扩展您的问题中的示例,显示“getConsumer”所在的类以及它是如何使用的(或简化版本),然后我将其包含在我的答案中。我展示的课程是为了这个课程。 – ggovan

+0

好像你正在把ARM类型的模式放在一起。我并不是真的在这里寻找。没有希望改变调用外部类的签名:实际上它是第三方的java lib。 – javadba