2014-03-04 30 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,但这只是将可变性移动一级。