2

在我的 Web 应用程序中,授权用户至少有 4 个“方面”:http 会话相关数据、持久数据、facebook 数据、运行时业务数据。

我决定使用案例类组合而不是特征至少有两个原因:

  • 特征混合可能导致名称冲突
  • 我想要免费的案例类好东西,比如模式匹配和复制方法

我想知道有经验的 scalaists 对此主题的看法。看起来特征和/或蛋糕模式应该适合此类任务,但正如我上面提到的那样存在问题......很明显,我不仅想快速轻松地实现它,而且还想深入理解它以供使用在未来。

那么我的决定是否有任何缺陷和误解,或者是否正确?相关代码如下所示:


case class FacebookUserInfo(name: String, friends: List[Long])
case class HttpUserInfo(sessionId: String, lastInteractionTime: Long, reconnect: Boolean)
case class RuntimeQuizUserInfo(recentScore: Int)
trait UserState {
  def db: User
  def http: HttpUserInfo
}

case class ConnectingUser(db: User, http: HttpUserInfo) extends UserState
case class DisconnectedUser(db: User, http: HttpUserInfo, facebook: Option[FacebookUserInfo]) extends UserState
case class AuthorizedUser(db: User, http: HttpUserInfo, facebook: FacebookUserInfo,
                          quiz: RuntimeQuizUserInfo) extends UserState
4

2 回答 2

3

我认为答案很简单:只要一切都真正“属于”您的对象,只要一切都在同一个“问题域”中,就使用继承。

蛋糕模式的目的是分解出对象的某些部分,这些部分在某种程度上是必需的,但实际上并不是它的一部分,例如策略、装饰、配置、上下文等。日志记录将是一个典型的例子。通常,我们谈论的是您不想“硬连线”事物的情况,例如您会考虑在 Java 中使用 DI 框架(如 Guice 或 Spring)的情况。有关一个很好的示例,请参见http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di.html

一个通常有助于决定做什么的问题是:“我如何测试对象的行为?”。如果你发现很难建立一个合适的测试环境,你可能需要解耦,那就是DI,这通常可以用蛋糕模式很方便地实现。

于 2010-10-07T07:40:18.873 回答
1

第三种选择是使用隐式转换器,即“ pimp my library ”,这可能不是必需的,因为您可以控制代码。

这完全取决于您希望对象的某些方面有多不透明(或透明)。您可以向世界其他地方假装它是一个普通的旧案例类,但在内部通过使用隐式使其做额外的工作。使用 case 类来保存数据是合适的,但我也觉得根据她的身份验证状态使用三个类 ( ConnectingUser, DisconnectedUser, ) 来表示同一个对象很尴尬。AuthenticatedUser

对于UserState,您可以提供一个提取器,使其表现得像一个案例类:

object UserState {
  def unapply(state: UserState) = Some(state.db, state.http)
}

这可以在匹配状态下使用,如下所示:

val user = ConnectingUser(User(), HttpUserInfo("foo", 0, false))
user match {
  case UserState(db, http) => println(http)
}
于 2010-10-08T16:22:35.377 回答