1

在 Lift中管理状态的一种典型方法是创建一个扩展 SessionVar 的单例对象,就像这个取自文档的示例一样:

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

使用SessionVars 的情况很清楚,我一直在根据需要在实践中使用它们。我也大致了解它们在内部是如何工作的。

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

尽管我现在了解它是如何工作的,但我无法理解这种设计的基本原理,至少对我而言,它违反了最小惊讶规则。有人能指出任何优势或解释为什么会做出这样的设计决定吗?

4

2 回答 2

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”对象,当您想要访问特定于会话的数据时必须使用该对象。不是很方便。

于 2013-06-06T22:23:13.523 回答
2

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

于 2013-06-07T12:58:24.210 回答