我有以下类,其属性为Option[T]
class User extends IdBaseEntity[UUID] { var id: Option[UUID] = None var name: Option[String] = None var createdOn: Option[Date] = None }
在某些数据访问层中,如果在将对象持久保存到cassandra之前未设置这些属性,则需要分配这些属性。以下是createdOn
属性的几种方法。这些都是最好的方法还是我应该做的更好?
示例1
entity.createdOn = Some(entity.createdOn.map(identity).getOrElse(new Date()))
示例2
entity.createdOn = entity.createdOn.orElse(Some(new Date()))
示例3
entity.createdOn = entity.createdOn match { case None => Some(new Date()) case _ => entity.createdOn }
示例4
entity.createdOn = entity.createdOn match { case None => Some(new Date()) case Some(x) => Some(x) }
示例5
entity.createdOn match { case None => entity.createdOn = Some(new Date()) case _ =>; }
答案 0 :(得分:4)
Option
上的匹配并不是真正的惯用语(恕我直言)。我更喜欢orElse
或getOrElse
。我个人会选择例子2。
我不确定这是否适合您的用例,但让User
成为一个不可变的案例类更为惯用:
case class User(id: Option[UUID] = None, ...)
和copy
它,而不是就地更新字段:
val updatedEntity = entity.copy(name = user.name.orElse(Some("Chris")))
答案 1 :(得分:1)
我会考虑改变你的设计 - 有两个原因:
看起来User类在初始化后应该是只读的,所以像case类或val而不是var这样的东西会捕获这个要求:
案例类用户(id:UUID,name:String,createdOn:Date);
看起来每个用户都需要设置id,name和createdOn属性,因此Option []不是建模的好方法。
我经常在旁边的只读类中设置一个Builder类 简化和解耦对象构造过程 对象代表什么 - 类似于 此
object User {
class Builder {
var id:UUID = UUID.randomUUID()
def id( v:UUID ):this.type = {id =v; this; }
var name:String = id.toString
def name( v:String ):this.type = { name=v; this; }
var createdOn:Date = new Date()
def createdOn( v:Date ):this.type = { createdOn = v; this; }
def build():User = {
assert( Seq(id,name,createdOn).find( _ == null ).isEmpty, "Must set all props" )
User( user, name, createdOn )
}
}
}
无论如何 - 这是另一种做事的方式......
答案 2 :(得分:1)
由于场景是“获取属性值并在某些条件成立时更新它”,我将尝试封装对属性的访问。例如:
/**
* Read+write access to property `P` of object `R`.
*/
case class Accessor[R,P](get: R => P, set: (R, P) => Unit) {
/** Utility for updating values. */
def update(record: R, modfn: P => P) =
set(record, modfn(get(record)));
}
class User {
var id: Option[Int] = None;
}
object User {
// For each property of `User` we need to define an accessor,
// but this is one time job:
val idA: Accessor[User,Option[Int]] =
Accessor((u: User) => u.id,
(u: User, r: Option[Int]) => u.id = r);
}
object Test {
import User._;
// We can do a lot of stuff now with accessors, for example set
// default values for `Option[...]` ones:
def setDefault[A,B](record: A,
accessor: Accessor[A,Option[B]],
defPropVal: => B) =
accessor.update(record, _.orElse(Some(defPropVal)));
val user = new User();
// Set user's id, if not defined:
setDefault(user, idA, 42);
}
因此,我们不是为每个属性定义一个特定的方法来填充默认值,而是为每个属性定义一个通用访问器。然后我们可以使用它们来实现所有其他的东西。