Scala:避免使用可变的实例变量

时间:2014-03-04 15:59:37

标签: scala playframework server-sent-events

我正在尝试避免类中的可变实例变量,但在尝试在我的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在这里是可以的,因为任何外部交互都无法修改它?

1 个答案:

答案 0 :(得分:0)

由于您的User类本身正在处理事件,因此它必须维护状态,这意味着它是可变的。

当外部力量完成 它们时,不可变类非常有用,例如MyController是否在用户中签名,并且可以创建user = user.copy(signedOn = true)。 如果类本身正在管理状态,那么,你需要可变性。

你可以通过用val替换你的布尔变量来获取所有AtomicBoolean,但这只会将可变性移动一级。