假设我们想建立一个庞大的社交网络(因为社交网络目前风靡一时)。我们将从一个简单的前提开始,任何想要使用我们的社交网络的人都应该能够以他们的名义注册,然后成为朋友或与其他注册的人一起退出:
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实现?
答案 0 :(得分:2)
是否有特殊原因需要使用db4o?与许多Java持久性框架一样,它假设对象中的可变性是可以的,这与惯用的Scala实际上不能很好地融合。
使用Squeryl或Akka能够处理的多个NoSQL存储之一,您可能会有更多的乐趣。如果没有进一步的信息,我可能会在这个阶段推荐Squeryl。
完成此操作后,您还需要避免在Person对象中保留双向朋友关系 - 他们将使不可变“更新”几乎不可能。将此信息提升为专用的Relationship
对象将有很大帮助,它还可以让您在系统发展过程中轻松添加有关关系本质的更多信息。
然后您的原始问题变得无关紧要:)
答案 1 :(得分:0)
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
}