我从关于这个主题的所有可用文章中得到的是,
不可变对象的主要优点是可以进行并发编程。所以如果任何应用程序使用这么多线程,那么我们可以使用不变性。
这里我的问题是:如果应用程序不需要多线程,仍然首选不可变编程吗?因为为每次更改创建对象的新副本可能非常昂贵。(如果是为什么)
考虑一下:
class Time(t: Double) {
private var time = t // Danger: mutable field
def getTime = time
def setTime(t: Double): Unit = time = t
}
val startAt = new Time(5.0)
val someOtherTime = startAt
someOtherTime.setTime(10.0)
// What does startAt.getTime return?
在这个简单的示例中,您可能(也可能不会)惊讶地发现,在someOtherTime.setTime(10.0)
返回后,startAt.getTime
将具有值10.0
而不是5.0
。你有没有预料到,特别是考虑到这startAt
是一个val
?
鉴于您已经看过代码,也许这是意料之中的。但是,如果您只是使用Time
而不查看其内部结构,我猜您会对这种行为感到非常惊讶。可变对象的状态可以在您不知情的情况下发生变化——特别是在多线程环境中,其中访问Time.time
必须同步——但即使是单线程情况也会引入意想不到的复杂性。
保持对象不可变使它们易于推理。当这些对象表示值类型时,不变性实际上是必不可少的。(在非不可变的任何主要编程语言或库中命名单个值类型。)
关于单线程与多线程编码的另一点是:如果您正在编写单线程应用程序,您可能会试图完全忽略线程安全作为一个问题。但是,我认为在一般情况下这有点短视。所有新处理器都有多个内核,并且有迹象表明处理器将在未来几年获得越来越多的内核。如果您想编写响应式、高性能的代码,您将需要使用线程安全库编写多线程应用程序。
如果您编写的代码不是线程安全的,并且它包含大量显示共享可变状态的可变对象,那么您将不得不进行大量重构以使其适用于多线程应用程序。另一方面,如果您的对象是不可变的,并且没有共享的可变状态,那么这项工作将变得容易得多。
顺便说一句,如果可变状态不是共享的(即外部可见),则完全有可能在函数、类等中使用可变状态。这样你就可以获得可变状态性能的好处,而没有缺点。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句