Scala Set实现在业务模型中使用?

时间:2010-10-21 14:55:23

标签: scala scala-2.8 db4o

假设我们想建立一个庞大的社交网络(因为社交网络目前风靡一时)。我们将从一个简单的前提开始,任何想要使用我们的社交网络的人都应该能够以他们的名义注册,然后成为朋友或与其他注册的人一起退出:

import scala.collection._

class Person (var name: String) {
    private val _friends = new mutable.HashSet[Person]

    def befriends     (p: Person) { _friends+=p }
    def fallsOutWith  (p: Person) { _friends-=p }
    def friends () = _friends toSet
    override def toString = name
}

到目前为止一切顺利:

val brad     = new Person("Brad Pitt")
val angelina = new Person("Angelina Jolie")

brad befriends angelina
angelina befriends brad 

好东西!最后一点,让我们看看Brad所有朋友的名单:

brad.friends.foreach(println)

它有效,而且我们即将通过我们精彩的社交网络(全部是100%Scala)来迎接世界!

现在谈论无聊的技术部分。我们需要能够持久保存数据,而db4o似乎是一个不错的选择,还有一些代码:

 db store brad // job done!

然后从硬盘中恢复Brad:

 val q = db.query       
 q.constrain(classOf[Person])
 q.descend("name").constrain("Brad Pitt")           
 val brad = q.execute.get(0)                

再次查看朋友列表......

 brad.friends.foreach(println)

和砰! 的NullPointerException 的!经过一些调试后发现,我们依赖跟踪朋友的mutable.HashSet的底层数据存储在 scala.collection.mutable.FlatHashTable <中定义为 transient / EM>:

@transient protected var table: Array[AnyRef] = new Array(initialCapacity) 

因此当我们告诉db4o存储一个Person时未实际序列化的朋友列表。似乎db4o应该使用HashSet的 readObject writeObject 方法。

我想知道是否有办法告诉db4o正确地序列化/反序列化HashSet,或者是否有更适合db4o友好的Scala Set实现?

2 个答案:

答案 0 :(得分:2)

是否有特殊原因需要使用db4o?与许多Java持久性框架一样,它假设对象中的可变性是可以的,这与惯用的Scala实际上不能很好地融合。

使用Squeryl或Akka能够处理的多个NoSQL存储之一,您可能会有更多的乐趣。如果没有进一步的信息,我可能会在这个阶段推荐Squeryl。

完成此操作后,您还需要避免在Person对象中保留双向朋友关系 - 他们将使不可变“更新”几乎不可能。将此信息提升为专用的Relationship对象将有很大帮助,它还可以让您在系统发展过程中轻松添加有关关系本质的更多信息。

然后您的原始问题变得无关紧要:)

答案 1 :(得分:0)

scala.collection.immutable.HashSet不会遭受同样的序列化问题,重写Person类依赖于不可变的HashSet解决问题:

import scala.collection._ 

class Person (var name: String) { 
    private var _friends = new immutable.HashSet[Person] 

    def befriends     (p: Person) { _friends=_friends+p } 
    def fallsOutWith  (p: Person) { _friends=_friends-p } 
    def friends () = _friends
    override def toString = name 
}