我知道不变性并不总是圣杯。但是,由于我现在正在学习Scala很长一段时间,所以我总是首先尝试找到一个不可变的解决方案,特别是在涉及纯粹的“数据对象”时。 我目前正在寻找为给定方案创建不可变对象图的方法,但我不确定这是否可行。
我只想创建一次图表,在创建之后更改是不必要的。
想象一下以下场景:
Person
。Person
个对象可以有两种类型的引用:
Person
类型)之间存在一个单向的1-n关系。 第一个问题是两个配偶之间的关系是循环的。因为设置引用导致新对象(由于不变性),最终配偶A指向配偶B_old并且配偶B指向配偶A_old。在另一篇帖子中有人说循环引用和不变性是矛盾的。我不认为这总是正确的,因为配偶A可以在自己的构造函数中创建配偶B并传递this
- 但即使使用这种不舒服的方法,之后添加子参考也会再次改变A和B.反过来 - 从孩子开始,然后连接配偶 - 导致类似的情况。
目前,我认为没有办法做到这一点。但也许我错了,有一些我不知道的模式或解决方法。如果不是,可变性是唯一的解决方案吗?
答案 0 :(得分:4)
我可以想象一下如何创建不可变循环的几个技巧,包括但不限于:
但是我最喜欢的那个(它是真正的scala-way)是经过仔细混合的懒惰评估和按名称参数:
object DeferredCycle extends App {
class C(val name:String, _child: => C) {
lazy val child = _child
override def toString: String = name + "->" + child.name
}
val a:C = new C("A", b)
val b:C = new C("B", a)
println(a)
println(b)
}
打印:
A->B
B->A
答案 1 :(得分:2)
要添加另一个透视图,您并不总是必须将关系建模为包含。您可以添加另一级别的间接,例如不透明的标识符。
case class PersonId(id: Int)
case class Person(id: PersonId, name: String, spouse: Option[PersonId], children: Seq[PersonId])
val people: Map[PersonId, Person] = ...
或者,关系甚至不需要是Person
的成员,也可以在外部维护:
case class PersonId(id: Int)
case class Person(id: PersonId, name: String)
val people: Map[PersonId, Person] = ...
val spouses: Map[PersonId, PersonId] = ...
val children: Map[PersonId, Seq[PersonId]] = ...