只读实体的Scala数据模型

时间:2012-12-12 05:34:28

标签: oop scala

我正在研究将在数据库中持久保存的实体。以User实体为例,我想以这种方式使用它们:

val userBeforePersisting = new User("Joe", "joe@gmail.com")

// DB access code (where rs is a ResultSet)
val foundUser = new User(rs.getLong("id"), rs.getString("name"), rs.getString("email"))

我想使用相同的用户代码(即最小化代码重复),同时拥有两种类型的用户:

  1. 预先保留的用户没有ID
  2. 从数据库检索到的持久用户具有ID
  3. 我想在编译时尽可能严格地执行此操作。

    我希望能够对所有用户进行相同的处理,除非我尝试从非持久用户获取ID,否则将引发错误或无法编译。

    我想避免像这样制作单独的课程

    class NewUser(val name: String, val email: String)
    class PersistedUser(val id: Long, val name: String, val email: String)
    

    由于代码重复(名称和电子邮件字段),我不喜欢这种解决方案。

    以下是我的想法:

    class User(val id: Long, val name: String, val email: String) {
      this(name: String, email: String) = this(0l, name, email)
      this(id: Long, name: String, email: String) = this(id, name, email)
    }
    

    但是,我的未坚持用户的id0l

    这是另一种方法:

    trait User {
      val name: String
      val email: String
    }
    
    class NewUser(val name: String, val email: String) extends User
    
    class PersistedUser(val id: Long, val name: String, val email: String) extends User
    

    这给了我想要的编译时检查。我不确定是否有任何退缩。

    也许我可以尝试这样的事情:

    class User(val name: String, val email: String)
    trait Persisted { val id: Long }
    class PersistedUser(val id: Long, val name: String, val email: String)
      extends User(name, email)
      with Persisted
    

    对这些方法的想法?我从来没有这样做过,所以我不确定我是否理解所有后果。

1 个答案:

答案 0 :(得分:3)

听起来像使用Option

class User(val id: Option[Long], val name: String, val email: String)

因此,持久用户的idSome(id),而非持久用户为None

为方便起见,您可以向id授予默认值None

class User(val id: Option[Long] = None, val name: String, val email: String)

// When you have an id...
val foundUser = new User(Some(rs.getLong("id")), 
    name = rs.getString("name"), email = rs.getString("email"))

// When you don't
val userBeforePersisting = new User(name = "Joe", email = "joe@gmail.com")

// However this will throw a runtime error:
val idThatDoesntExist: Long = userBeforePersisting.id.get

这也适用于您的多构造函数示例:

class User(val id: Option[Long], val name: String, val email: String) {
  def this(name: String, email: String) = this(None, name, email)
  def this(id: Long, name: String, email: String) = this(Some(id), name, email)
}

我认为Option可能有意义,因为您想在同一个类中表达某个字段可能具有值的。唯一的另一种方式似乎是拥有两个类(可能一个继承自另一个),只有一个具有id字段。