2014-06-05 81 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