2013-11-04 83 views
3

使用Futures和Promises進行延遲初始化,而不是使用Option var或某個可變變量是否合適?適合使用期貨和承諾進行延遲初始化?

您可以創建一個工廠類,封裝了承諾:

class IntFactory{ 
    val intPromise = Promise[Int] 
    def create() : Future[Int] = intPromise.future 
    def init (data : String) : Unit = intPromise success data.length 
} 

一個演員,然後一些其他類可以這樣使用它:

class MyActor(factory : IntFactory) extends Actor{ 
    val future_int = factory.create() 

    def receive = { 
    case (msg : String) => factory.init(msg) // Now the promise is fulfilled 
    } 
} 

有什麼不妥做這樣的事情這個?用演員作爲例子可能並不理想,因爲我認爲演員(成爲或FSM)有更好的選擇。我目前正在考慮將此與非演員課程一起使用。除非發生某些事件,否則某些實例變量是無效的。我正在考慮這樣做,而不是使用var Option並將其設置爲None。如果這是不好的,還有其他的選擇嗎?

編輯:

我想到的地方,這可能是比較有用的情況。如果我有一個需要進行初始化多的東西,我有,我想執行的時候就一切都安排一些異步操作:

class MyActor(factory1 : IntFactory, factory2 : IntFactory) extends Actor{ 
    val future_int1 = factory1.create() 
    val future_int2 = factory2.create() 

    for{ 
    x <- future_int1 
    y <- future_int2 
    } // Do some stuff when both are complete 

    def receive = { 
    case "first" => factory1.init("first") 
    case "second" => factory2.init("second") 
    } 
} 

那我就不必檢查哪些每次我得到的時間都沒有另一塊。

多個編輯:

,我失敗我原來的問題,指定一些額外的信息:

  1. 初始化的對象會在異步所需的數據。

  2. 傳遞給init函數的數據是初始化所必需的。我編輯了我的示例代碼,以便現在是這種情況。

  3. 我沒有使用Akka。我認爲阿卡會有助於把一個快速的例子放在一起,並認爲經驗豐富的阿卡人可以提供有用的反饋。

+0

這是對構建器模式的一個很好的閱讀 - 當某個東西一次初始化一塊時使用,我從來沒有使用它,但是很酷的是它可以在運行前完成 - 所以如果你遇到編譯器錯誤嘗試訪問太早:http://nullary.blogspot.com/2011/10/builder-pattern-revisited-in-scala.html – LaloInDublin

+0

不會只是'懶惰val'就足夠了嗎? –

+0

@PatrykĆwiek你可以用懶惰的val重寫這個例子嗎?我不知道我會怎麼做。我不確定它會起作用,因爲我的初始化取決於來自外部異步事件的數據。 – mushroom

回答

2

是的,這肯定是比使用可變的變量更好的辦法(是否Option與否)。正如@ Patryk?wiek所建議的那樣,使用lazy val,如果您可以隨時初始化狀態,而不是等待外部事件,並且不需要異步執行,那麼它會更好。

0

IntFactory來看,你並不真正需要的data字符串(它沒有任何地方使用),所以我認爲基本情況可以改寫這樣的:現在

class Foo { 
    lazy val first = { 
    Thread.sleep(2000) // Some computation, initialization etc. 
    25 
    } 
    lazy val second = { 
    Thread.sleep(1000) // Some computation, initialization etc. 
    11 
    } 
    def receive(s : String) = s match { 
    case "first" => first 
    case "second" => second 
    case _ => -1 
    } 
} 

,讓我們說你這樣做:

val foo = new Foo() 
println(foo.receive("first")) // waiting for 2 seconds, initializing 
println(foo.receive("first")) // returns immediately 
println(foo.receive("second")) // waiting for 1 second, initializing 

現在無論firstsecond可以初始化最多一次

您不能將參數傳遞給lazy val s,所以如果data字符串對初始化非常重要,那麼使用工廠方法和記憶(IMO)可能會更好。

+0

當我真正使用它時,需要init的輸入。我的例子並不是很明確。我試圖儘可能簡化這個例子,並且走得太遠了。我將通過memoization調查工廠方法。 – mushroom