oop - 可变对象与不可变对象(immutable对象)

标签 oop immutability mutable

我正在尝试了解可变对象与不可变对象(immutable对象)。使用可变对象会受到很多负面影响(例如从方法返回字符串数组),但我很难理解这样做的负面影响。使用可变对象的最佳实践是什么?您应该尽可能避免它们吗?

最佳答案

嗯,这有几个方面。

  1. 没有引用标识的可变对象可能会在奇怪的时候导致错误。例如,考虑一个具有基于值的 equals 方法的 Person bean:

    Map<Person, String> map = ...
    Person p = new Person();
    map.put(p, "Hey, there!");
    
    p.setName("Daniel");
    map.get(p);       // => null
    

    Person 实例在用作键时会在映射中“丢失”,因为它的 hashCode 和相等性基于可变值。这些值在 map 之外发生了变化,所有散列都变得过时了。理论家喜欢在这一点上喋喋不休,但在实践中我并没有发现这是什么太大的问题。

  2. 另一个方面是代码的逻辑“合理性”。这是一个很难定义的术语,涵盖了从可读性到流程的所有内容。一般来说,您应该能够查看一段代码并轻松理解它的作用。但比这更重要的是,您应该能够说服自己它所做的事情正确。当对象可以在不同的代码“域”之间独立更改时,有时很难跟踪内容、位置和原因(“spooky action at a distance”)。这是一个更难举例说明的概念,但在更大、更复杂的架构中经常会遇到这种情况。

  3. 最后,可变对象在并发情况下是 killer 。每当您从单独的线程访问可变对象时,您都必须处理锁定。这会降低吞吐量,并使代码显着更难以维护。一个足够复杂的系统会使这个问题变得不成比例,以至于几乎不可能维护(即使对于并发专家来说也是如此)。

不可变对象(immutable对象)(更具体地说,不可变集合)避免了所有这些问题。一旦你了解了它们的工作原理,你的代码就会变得更容易阅读、更容易维护,并且不太可能以奇怪和不可预测的方式失败。不可变对象(immutable对象)甚至更容易测试,这不仅是因为它们易于模拟,而且还因为它们倾向于强制执行的代码模式。简而言之,它们都是很好的实践!

话虽如此,我对这件事并不是一个狂热分子。当一切都是不可变的时,有些问题就无法很好地建模。但我确实认为您应该尝试将尽可能多的代码推向这个方向,当然假设您使用的语言使这一观点站得住脚(C/C++ 使这变得非常困难,Java 也是如此) 。简而言之:优势在某种程度上取决于您的问题,但我倾向于更喜欢不变性。

关于oop - 可变对象与不可变对象(immutable对象),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/214714/

相关文章:

oop - 如何避免 getter 和 setter

php - 在 PHP 的 OOP 编程中设置我的类的正确方法是什么?

scala - 为什么 Scala 不可变的 HashMap 方法返回一个 Map?

constants - D 中的逻辑常量

arrays - 从 Scala 中的 for 循环生成 ArrayBuffer(或其他可变 Collection 类型)

c++ - 处理 C++ 类中的惰性计算

c# - 关键字 NEW 会重新初始化所有其他在 C# 中运行的函数值吗?

perl - 在 Perl 中重载 '='

dictionary - 在 Elixir 中存储状态

java - 我可以告诉 Hibernate 一个类是不可变的,以便它共享对象以节省构造成本吗?