2012-12-12 44 views
1

我正在建模将保留在数据库中的实体。使用用户实体作为一个例子,我想用这种方式与他们一起工作:只读实体的Scala数据模型

val userBeforePersisting = new User("Joe", "[email protected]") 

// 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

我想在编译时尽可能严格执行这一点。

我希望能够对待所有用户相同,除非我尝试从未保留的用户获取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) 
} 

但后来我未坚持用户有0lid

这里的另一种方法:

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 

任何思考这些方法?我从来没有这样做过,所以我不确定我是否理解了所有的后果。

+0

你不喜欢最后一种方法?是'val name:String,val email:String'出现两次的次要代码重复吗? – Faiz

回答

3

听起来像可能使用Option

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

所以坚持用户拥有的Some(id)id而非持续的用户有None

为方便起见,你能给idNone默认值:

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 = "[email protected]") 

// 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字段。

+0

感谢您的反馈@Faiz。我曾考虑过Options,我认为这是一个好方法。我不喜欢这种方法的事情是,我对用户的大部分处理都是持久用户,我想避免所有的.get调用。我确实给了你一票,因为这是一个可靠的解决方案。 –

+0

@three_cups_of_java我明白了 - 好吧,我猜''Option'的惯用用法通常会避开'.get'来支持'foreach' /'map' /'filter'等 - 但我现在明白你想要一个'PersistedUser '类你认为理所当然'ID'字段表示一个真实的ID保持。 – Faiz