我试图避免类中的可变实例变量,但我无法弄清楚在以下情况下如何在我的 Play 应用程序中创建用户:
当用户登录时,像 membershipList 这样的用户信息可以改变。当这样的事情改变时,应用程序使用 Play 的 Ok.feed(...)
作为服务器发送事件通知用户(上交所)。
编辑:@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
}
Controller 中的 Action 将是:
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 的枚举器有关。每当用户信息发生变化时,我都会创建一个新的用户对象,但我会从同一用户的先前实例复制单播枚举器。当创建新的用户实例时,Json 将被推送到用户的单播 channel 中一次。
也许在这里将 infoSentOnce
作为 var 是可以的,因为它不能被任何外部交互修改?
最佳答案
由于您的 User
类本身正在处理事件,因此它必须保持状态,这意味着它是可变的。
不可变类在外部力量完成事情时最有用,比如如果 MyController
正在登录用户,并且可以使 user = user.copy(signedOn = true)
。
如果类本身正在管理状态,那么,您就需要可变性。
您可以通过用 AtomicBoolean
替换您的 bool 变量来在此处作弊以获取所有 val
,但这只会将可变性移到一个级别。
关于Scala:避免可变实例变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22176822/