Scala 在某些情况下,是否不可能创建不变的对象图?
我知道不变性并不总是圣杯。然而,由于我学习Scala已经有一段时间了,所以我总是首先尝试找到一个不变的解决方案,特别是当涉及到纯“数据对象”时。 我目前正在寻找一种为给定场景创建不可变对象图的方法,但我不确定这是否可行 我只想创建一次图形,创建后的更改是不必要的 想象一下以下场景:Scala 在某些情况下,是否不可能创建不变的对象图?,scala,functional-programming,immutability,object-graph,Scala,Functional Programming,Immutability,Object Graph,我知道不变性并不总是圣杯。然而,由于我学习Scala已经有一段时间了,所以我总是首先尝试找到一个不变的解决方案,特别是当涉及到纯“数据对象”时。 我目前正在寻找一种为给定场景创建不可变对象图的方法,但我不确定这是否可行 我只想创建一次图形,创建后的更改是不必要的 想象一下以下场景: 只有一种类型:Person Person对象可以有两种类型的引用: 一个人和潜在儿童之间存在单向1-n关系(也属于Person) 此外,妻子有丈夫,反之亦然 第一个问题是配偶之间的关系是循环的。因为设置引用会
- 只有一种类型:
Person
对象可以有两种类型的引用:Person
- 一个人和潜在儿童之间存在单向1-n关系(也属于
)李>Person
- 此外,妻子有丈夫,反之亦然
- 一个人和潜在儿童之间存在单向1-n关系(也属于
this
——但即使使用这种不舒服的方法,在之后添加子引用也会再次更改A和B。另一种方式——从孩子开始,然后将配偶联系起来——也会导致类似的情况
目前,我认为没有办法做到这一点。但也许我错了,有些模式或变通方法我不知道。如果不是,可变性是唯一的解决方案吗?我可以想象一些技巧如何创建不可变循环,包括但不限于:
- 私有可变类,它实际上是从外部不可变的
- 倒影
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
要添加另一个透视图,您不必总是将关系建模为包含。您可以添加另一级别的间接寻址,例如不透明标识符
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]] = ...
谢谢,非常有用。只有一个问题:您在创建
a
(referenceingb
)实例时所做的“正向引用”只起作用,因为b
是延迟周期
对象的属性,对吗?因此,如果a
尤其是b
只是方法内部的局部变量,那么这就不起作用了。还是我在这一点上错了?@DaniW,你是对的,但是你可以使用无数的技巧来克服这个限制。您可以在方法内部创建本地对象,您可以将这些类定义为var
s(然后可以选择重新定义为val
s),您可以将它们创建为某些集合的元素,等等。@Aivean我想知道“私有可变类”是什么样子。它是否有点像只能使用一次的可变setter,或者通过布尔标志控制?编辑:类似于set(c:Child):Unit={if(switch)this.Child=c;switch=false}
?@ceran,您的方法也是可行的,但更接近于“验证不变量”。我所说的“私有可变类”实际上是指私有setter,它只能从创建实例的地方访问,比如一些工厂。当实例离开工厂时,可以认为它实际上是不可变的,因为setter是私有的。我在问题中没有说的是,Person
有几个子类型。如果引用只由ID完成,我想我会失去相当多的类型安全性。我想更新你的帖子,但我需要先获得15学分:/