Scala 设置在业务模型中使用的实现?

发布于 2024-09-28 04:08:51 字数 1581 浏览 2 评论 0原文

假设我们想要建立一个大型社交网络(因为社交网络目前非常流行)。我们将从一个简单的前提开始,即任何想要使用我们的社交网络的人都应该能够以自己的名义注册,然后成为朋友或与其他在我们这里注册的人闹翻:

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)

然后砰! 空指针异常!经过一些调试,我们发现我们用来跟踪朋友的 mutable.HashSet 的底层数据存储在 scala.collection.mutable.FlatHashTable< 中被定义为 transient /em>:

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

因此,当我们告诉 db4o 将 Person 存储为未序列化的实际朋友列表时。看来 db4o 应该使用 HashSet 的 readObjectwriteObject 方法。

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

Let's say we want to build a big social network (because social networks are all the rage at the moment). We'll start with a simple premise that anyone who wants to use our social network should be able to register under their name and then become friends or fall out with other people registred with us:

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
}

So far so good:

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

brad befriends angelina
angelina befriends brad 

Good stuff! A final touch, let's see the list of all Brad's friends:

brad.friends.foreach(println)

It works, and we're about to take the world by a storm with our wonderful social network that is all 100% Scala!

Now on to the boring, technical bits. We'd need to be able to persist data and db4o seems as a good choice, some more code:

 db store brad // job done!

And then restore Brad from hard drive:

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

See the list of friends once again...

 brad.friends.foreach(println)

and BANG! NullPointerException! With a bit of debugging it turns out that underlying data store of mutable.HashSet that we're relying on to keep track of friends is defined as transient in scala.collection.mutable.FlatHashTable:

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

and hence when we telling db4o to store a Person the actual list of friends in not serialised. It seems that db4o ought to be using readObject and writeObject methods of HashSet instead.

I wonder if there is way of telling db4o to serialise / deserialise HashSet correctly or if there is a more suitable Scala Set implementation that is db4o friendly?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

时光与爱终年不遇 2024-10-05 04:08:51

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

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

完成此操作后,您还需要避免 Person 对象中保存的双向好友关系 - 它们将使不可变的“更新”几乎不可能。将此信息提升到专用的 Relationship 对象中将有很大帮助,它还允许您随着系统的发展轻松添加有关关系性质的更多信息。

那么你原来的问题就变得无关紧要了:)

Is there a particular reason why you need to use db4o? As with many Java persistence frameworks, it assumes that mutability in objects is okay, which really doesn't mesh too well with idiomatic Scala.

You might have more joy using Squeryl or one of the multiple NoSQL stores that Akka is able to deal with. In absence of further information, I'd probably recommend Squeryl at this stage.

Having done that, you'll also want to avoid the bidirectional friend relationships held in your Person objects - they'll make immutable "updates" almost impossible. Lifting this information into a dedicated Relationship object will help out a great deal, it'll also allow you easily add more information about the nature of relationships as your system evolves.

Your original question then becomes irrelevant :)

追我者格杀勿论 2024-10-05 04:08:51

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 
} 

scala.collection.immutable.HashSet doesn't suffer from the same serialisation issue, re-writing Person class to rely on the immutable HashSet solves the problem:

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 
} 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文