2

我有以下类,其中属性是Option[T]

类用户扩展 IdBaseEntity[UUID] {
  变量 ID:选项 [UUID] = 无
  变量名称:选项 [字符串] = 无
  var createdOn: 选项 [日期] = 无
}

在某些数据访问层中,如果在将对象持久保存到 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 匹配 {
  case None => Some(new Date())
  case _ => entity.createdOn
}

示例 4

entity.createdOn = entity.createdOn 匹配 {
  case None => Some(new Date())
  案例一些(x) => 一些(x)
}

示例 5

entity.createdOn 匹配 {
  case None => entity.createdOn = Some(new Date())
  案例_ =>;
}
4

3 回答 3

4

匹配Option并不是真正地道的(恕我直言)。我更喜欢得到orElseor getOrElse。我个人会选择示例 2。

我不确定这是否适合您的用例,但创建User一个不可变的案例类更为惯用:

case class User(id: Option[UUID] = None, ...)

它,而copy不是就地更新字段:

val updatedEntity = entity.copy(name = user.name.orElse(Some("Chris")))
于 2013-04-30T23:25:54.167 回答
1

我会考虑稍微改变你的设计 - 有两个原因:

  • 看起来 User 类在初始化后应该是只读的,所以像 case class 或 val 而不是 var 之类的东西会满足这个要求:

    case class User(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 )
       }
   }
}

无论如何 - 这是另一种做事方式......

于 2013-05-01T02:46:51.427 回答
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);
}

因此,我们不是为每个属性定义一个特定的方法来填充默认值,而是为每个属性定义一个通用访问器。然后我们可以使用它们来通用地实现所有其他的东西。

于 2013-05-01T08:48:22.783 回答