我喜欢不可变的概念,但有时我想知道,当应用程序不应该是并行的时,是否应该避免使事物不可变?
当应用程序不是多线程时,您不会受到共享状态问题的困扰,对吧?
或者不变性是一个像 OOP 这样的概念,你要么一直使用,要么不使用?排除基于使用/性能等不应该不可变的情况。
我在为自己编写应用程序时遇到了这个问题,这个问题比较大(可能像 1-2k 行)。
我喜欢不可变的概念,但有时我想知道,当应用程序不应该是并行的时,是否应该避免使事物不可变?
当应用程序不是多线程时,您不会受到共享状态问题的困扰,对吧?
或者不变性是一个像 OOP 这样的概念,你要么一直使用,要么不使用?排除基于使用/性能等不应该不可变的情况。
我在为自己编写应用程序时遇到了这个问题,这个问题比较大(可能像 1-2k 行)。
我喜欢不变性的优势,即您只需要验证一次 - 在创建对象时。这实际上是一个巨大的奖金。
我喜欢不变性,因为这意味着我不必相信其他人的代码不会弄乱我希望保持不变的对象。
当您将对象传递给另一个组件(例如 a List<T>
)时,您将受制于该组件的作用。当您将集合作为属性返回时,这一点尤其重要。
public class Foo {
private List<Bar> _barList;
public ICollection<Bar> BarList { get return _barList; }
}
没有什么能阻止这个类的消费者从我下面清除集合。即使将返回类型切换IEnumerable<Bar>
为也不完全安全。没有什么可以阻止一些写得不好的代码将其转换回List<T>
并调用 .Clear()。
但是,如果我真的希望集合保持一致,我可以将其重写如下
public class Foo {
private ImmutableCollection<Bar> _barList;
public ImmutableCollection<Bar> BarList { get { return _barList; } }
}
现在我不必相信其他代码不会错误地使用我的类。他们不能搞砸了。
不变性的一个主要好处是不需要跟踪不可变对象的所有权。只要有人需要它们,它们就存在,然后在不再需要它们时消失在虚无中。虽然在许多情况下使用垃圾收集器意味着不需要编写任何明确的代码来处理可变对象的所有权(最大的例外是那些实现IDisposable
),但在许多情况下很难编写正确的代码,其中对象具有可变国家没有一个明确定义的“所有者”。关于谁拥有可变对象状态的混淆可能是一个非常常见的错误来源。当使用不可变对象时(除了一些实现的对象IDisposable
),通常可以忽略所有权问题。
要考虑的另一点是,推理对语义不可变对象的可变引用或对可变对象的不可变引用比推理对可变对象的可变引用要容易得多。如果有一个对可变对象的可变引用,通常可能不清楚更新状态的正确方法是直接改变对象,还是将其状态复制到一个新对象,改变它,然后更新引用。在某些情况下,有些情况需要每种类型的操作(如List<T>
,有时会用更大的数组替换数组,但通常会就地更新),但这种方法只有在类型保持对相关可变对象的独占控制时才有效。拥有对可变类型的不可变引用通常更有帮助(在这种情况下,代码可能会通过只读包装器将引用公开给其他想要“实时查看”其状态的对象)或拥有对不可变对象的可变引用,或者至少在引用的生命周期内永远不会改变。