我正在尝试避免类中的可变实例变量,但在尝试在我的Play应用程序中创建用户时,我无法弄清楚以下情况:
在用户登录时,像membership列表这样的用户信息可以更改。当这样的事情发生变化时,应用程序会使用Play的Ok.feed(...)
作为服务器发送事件(SSE)通知用户。
编辑:@drstevens指出必须移出单播Feed,因为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 :(得分:0)
由于您的User
类本身正在处理事件,因此它必须维护状态,这意味着它是可变的。
当外部力量完成 它们时,不可变类非常有用,例如MyController
是否在用户中签名,并且可以创建user = user.copy(signedOn = true)
。
如果类本身正在管理状态,那么,你需要可变性。
你可以通过用val
替换你的布尔变量来获取所有AtomicBoolean
,但这只会将可变性移动一级。