2014-03-04 47 views
3

我試圖避免在課堂可變實例變量,但我無法弄清楚如何在下列情況下,同時試圖在我的播放應用程序中創建一個用戶:斯卡拉:避免可變實例變量

用戶信息例如membershipList可以在用戶登錄時更改。當這種情況發生變化時,應用程序將使用Play的Ok.feed(...)作爲服務器發送事件(SSE)通知用戶。

編輯:@drstevens指出,必須將單播饋送移出,因爲User顯示爲Case類。編輯User不是案例分類。在控制器

class User(id: Long, firstName: String, lastName: String, 
      membershipList: List[Group], @volatile private var signedIn = true) { 
    private var infoSentOnce = false; 
    private val unicastFeed: Option[Enumerator[JsValue]] = if(signedIn) Concurrent.unicast[JsValue](onStart, onComplete, onError) else None 

    private def onStart(channel: Channel[JsValue]) { 
    if(signedIn) { 
     if(!infoSentOnce) { 
     channel.push(json) 
     channel.end 
     infoSentOnce = true; 
     } 
    } else { 
     channel.eofAndEnd 
    }   
    } 

    private def onComplete = .... 

    private def onError(message: String, iteratee: Iteratee[JsValue]) = ..... 

    def json = { 
    ..... 
    } 

    def signedOut = signedIn = false 

    def feed = unicastFeed 
} 

行動將是:

class MyController extends Controller with MyAuth { 
    def userFeed = Authenticated { request => 
    request.user.feed.fold(Ok(request.user.json)) { feed => 
     Ok.feed(feed 
       >& Concurrent.buffer(10) 
       >& new EventSource()).as("text/event-stream")) 
    } 
    } 
} 

signedIn & infoSentOnce是兩個可變的變量,我想改變它是不可變的。可變的infoSentOnce也可能與我沒有正確理解Play的枚舉器有關。每當用戶信息發生變化時,我都會創建一個新的User對象,但是我會從同一用戶的前一個實例複製Unicast枚舉器。在創建新用戶實例時,Json將被推入用戶的單播頻道。

也許有infoSentOnce因爲var在這裏沒問題,因爲它不能被任何外部交互修改?

+0

你有沒有一個完整的例子,你正在嘗試做什麼?如何使用枚舉器?何時使用?我仍然會嘗試將'Enumerator'部分與'User'分開。 – drstevens

+0

@drstevens更新了問題的更多細節。 – Prasanna

+0

如果你想做一次不可變的初始化,那麼'lazy val'就可以做到這一點。它只能分配一次。 –

回答

0

由於User類正在處理事件本身,它必須保持狀態,這意味着可變。當事情做

不可變類是最有用的他們通過外部力量,就像如果MyController登入的用戶,並且可以使user = user.copy(signedOn = true)。 如果類本身在管理狀態,那麼,你需要可變性。

你可以在這裏作弊,通過用AtomicBoolean代替你的布爾變量來獲得所有的vals,但這只是將可變性移動一級。