在我的网络应用程序中,授权用户至少有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
答案 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类来保存数据是合适的,但我也觉得使用三个类(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)
}