为什么使用单例实现Lift中的SessionVars?

时间:2013-06-06 22:12:34

标签: scala session-variables lift

managing state in Lift的一种典型方法是创建一个扩展SessionVar的单例对象,就像这个取自the documentation的例子一样:

object MySnippetCompanion {
  object mySessionVar extends SessionVar[String]("hello")
}

使用SessionVar的情况很清楚,我已经根据需要在实践中使用它们。我也大致了解它们是如何在里面工作的。

尽管如此,我还是不禁想知道为什么“会话变量”的机制明显与当前会话相关联(通常只是系统中许多会话中的一个),它被设计为通过单例使用?这与我的直觉相反,乍一看我很想相信Lift能够以某种方式覆盖Scala的语言特征,并使object与常规Scala有所不同。

即使我现在明白它是如何运作的,但我无法理解这样一种设计的理由,至少在我看来,它打破了最不惊讶的规则。有人可以指出任何优势,或者解释为什么可以做出这样的设计决定吗?

2 个答案:

答案 0 :(得分:5)

Lift中的会话变量使用Scala的DynamicVariable。基本上它们允许您静态引用代码块中的变量,然后调用代码并替换值:

import scala.util.DynamicVariable

val x = new DynamicVariable(1)

def printIt() {
  println(x.value)
}

printIt()
//> 1

x.withValue(2)(printIt())
//> 2

因此,每次处理请求时,这些动态变量的范围都会更改为当前会话,完全将当前会话的状态更改隐藏为程序员。

另一种选择是传递一个“sessionID”对象,当您想要访问会话特定数据时,必须使用该对象。不太方便。

答案 1 :(得分:2)

您必须使用object关键字的原因是object是唯一的,因为它定义了值和类。这允许Lift调用getClass来获取唯一标识此SessionVar与其他任何名称相对应的名称,Lift需要这些名称以便在正确的位置序列化和反序列化每个会话状态。此外,如果SessionVar在具有两个实例的类中(例如,在两个选项卡中呈现的片段),则它们都将引用相同的会话状态。 (硬币的另一面是,两个不同的会话可以引用相同的SessionVar实例,并且对每个会话都是正确的。) 实际上有时这是不够的 - 例如,如果你在一个特征中定义一个SessionVar,并且有两个不同的类来继承这个特征,但你需要它们两个有两个不同的值。在这种情况下,解决方案是覆盖“名称盐”的def,它与getClass结合使用以识别SessionVar