Scala特征/蛋糕模式与案例类别

时间:2010-10-07 06:39:40

标签: scala traits case-class

在我的网络应用程序中,授权用户至少有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

2 个答案:

答案 0 :(得分:3)

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

蛋糕图案的意图是将某些部分的物品分解出来,但不是真正的一部分,例如:策略,装饰,配置,上下文等。记录将是一个典型的例子。一般来说,我们谈论的是你不想“硬连线”的情况,例如:您可以考虑在Java中使用DI框架(如Guice或Spring)。请参阅http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di.html以获取一个好例子。

通常有助于决定做什么的问题是:“我如何测试对象行为?”。如果您发现很难建立一个合适的测试环境,那么您可能应该将事物分离,这意味着DI,这通常可以通过蛋糕模式方便地实现。

答案 1 :(得分:1)

第三个选项是使用隐式转换器aka“pimp my library”,这可能是没有必要的,因为你可以控制代码。

这完全取决于你想要对象的某些方面不透明(或透明)。你可以假装它是一个普通的旧案例类到世界其他地方,但内部使它通过使用implicits做额外的工作。使用case类来保存数据是合适的,但我也觉得使用三个类(ConnectingUserDisconnectedUserAuthenticatedUser)表示相同的对象很尴尬,具体取决于她的身份验证状态

对于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)
}