好吧,这有几个方面。
- 没有参考身份的可变对象会在奇数时间导致错误。例如,考虑
Person
使用基于值的equals
方法的bean
:
Map<Person, String> map = ...Person p = new Person();map.put(p, "Hey, there!");p.setName("Daniel");map.get(p); // => null当
Person实例用作键时,实例在映射中“丢失”,因为实例
hashCode和相等性基于可变值。这些值在映射之外更改,并且所有散列都已过时。理论家喜欢在这一点上竖琴,但实际上,我并没有发现这是一个太大的问题。
另一方面是代码的逻辑“合理性”。这是一个很难定义的术语,涵盖了从可读性到流程的所有内容。通常,您应该能够查看一段代码并轻松了解其功能。但是比这更重要的是,您应该能够使自己相信它可以正确地完成工作。当对象可以在不同的代码“域”中独立更改时,有时会变得难以掌握位置和原因(“诡异的动作”)。这是一个更难以例证的概念,但是在更大,更复杂的体系结构中经常会遇到这个问题。
最后,可变对象在并发情况下是致命的。每当您从单独的线程访问可变对象时,都必须处理锁定。这减少了产量,使你的代码大大更难维护。一个足够复杂的系统将这个问题严重地夸大了,以致几乎无法维护(即使对于并发专家而言)。
不变的对象(尤其是不变的集合)避免了所有这些问题。一旦您了解了它们的工作原理,您的代码就会发展为易于阅读,易于维护且不太可能以奇怪和不可预测的方式失败的代码。不可变对象不仅因为其易于模拟性,而且由于它们倾向于强制执行的代码模式而更易于测试。简而言之,它们是一个很好的实践!
话虽如此,我在这件事上并不是狂热者。当所有事物都是不可变的时,有些问题只是无法很好地建模。但是我确实认为您应该尝试朝该方向尽可能多地推送代码,当然,前提是您所使用的语言使这种观点站得住脚(C / C ++和Java一样使这一点非常困难) 。简而言之:优势在某种程度上取决于您的问题,但是我倾向于不变性。



