- 我熟悉不可变性并且可以设计不可变类,但我主要拥有学术知识,缺乏实践经验
- 请参考上面的链接图片(尚不允许嵌入)
- 从下往上看
- 学生需要新地址
- 我们并没有真正改变学生,而是创建一个包含新地址的新学生
- mutator 方法返回这个新对象
Question:假设变异器调用来自不可变对象,如何处理这个新对象?
- 新学生无法保存在 Lecture 中,因为 Lecture 也是不可变的
- 所以我们还需要一个新的讲座,其中包含新的学生
- 但是在哪里保存新的讲座呢?
- 当然是在新学期,但它在哪里结束呢?
- 至少可以通过使用组件外观模式来打破该链,该模式处理所有新对象的创建,而不必通过整个链转发调用
Question: 到哪里停呢?是否必须在某个地方有一个可变对象才能至少保存最顶层的实例?
这就是函数式编程的思想。一切都是不可变的,任何函数调用都不允许有副作用。改变复杂对象的唯一方法(如您的示例中)是重新创建父对象。
现在的问题是如何改变程序状态。因此,我们首先想到的是栈。它包含所有局部变量的值以及被调用函数的所有参数的值。我们可以通过调用新函数来创建新值。我们可以通过从函数返回来丢弃值。因此,我们可以通过调用函数来改变程序状态。然而,并不总是可以从函数返回来丢弃其局部变量,因为我们可能只想丢弃一些局部变量,但需要保留其他局部变量的值以供进一步操作。在这种情况下,我们根本无法返回,但我们需要调用另一个函数并仅将一些局部变量传递给它。现在,为了防止堆栈溢出,函数式语言有一个称为尾调用优化的功能,它能够从调用堆栈中删除不必要的条目。如果关联函数唯一需要做的事情就是返回自身调用的函数的值,则不需要调用堆栈条目。在这种情况下,保留调用堆栈条目是没有意义的。通过删除不必要的调用堆栈条目,其他未使用的局部变量的值将被丢弃。您可能想阅读相关内容here https://en.wikipedia.org/wiki/Tail_call. Also, 尾递归 https://stackoverflow.com/questions/33923/what-is-tail-recursion与此有关。
同样,这是纯函数式编程语言的想法,例如Haskell https://www.haskell.org/。一切都是不可变的,这真的很好,但是这些语言有它们唯一的问题和它们自己的处理这些问题的方法。例如,Monad(以及更高种类的类型)在这些语言中可用,但在命令式/面向对象编程语言中很少见到。
我喜欢在程序内存的叶子上有不可变的值。但是,组成这些不可变值(实际上形成应用程序逻辑)的代码确实包含可变状态。对我来说,这结合了两个世界的优点。然而,这似乎是一个偏好问题。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)