Java周二生效! 最小化可变性

今天的主题是关于可变性以及使价值对象不可变所能带来的好处。 我认为这是一个很好的话题,因为它非常简单,并且可以使应用程序的许多其他部分也变得更简单。 多么奇妙的组合!

不变对象的概念很简单,它是一旦创建就无法修改的对象。 Java的平台库提供了一些不可变类的示例,例如串,大十进制,大整数,and the boxed primitive types. So why would you choose to make something immutable? Isn't removing capabilities a bad thing? Well,as interestingly often turns out to be the case,removing the capability to do something actually can make other things much simpler and safer. Before jumping into what immutability gives us let's talk about how to make a class immutable.

  1. 不要提供改变状态的方法:通常称为mutators或setter。确保不能扩展类最常见的做法是将课程定级。使所有字段为最终字段:明确表示希望内部状态不会发生变化。 将状态从一个线程传递到另一线程时,也有帮助。将所有字段设为私有:如果您遵循以下其他指导,则可能会这样做有效的Java并且出于所有相同的原因,在此我们遵循此指南。确保以独占方式访问可变状态:如果您的不可变对象通过访问器提供可变状态,则它必须通过制作防御性副本来保护其内部状态。

让我们看一个例子:

@Getter
public final class ComplexNumber {
  private final double real;
  private final double imaginary;

  public ComplexNumber(double real, double imaginary) {
    this.real = real;
    this.imaginary = imaginary;
  }

  public ComplexNumber plus(ComplexNumber other) {
     return new ComplexNumber(this.real + other.real, this.imaginary + other.imaginary);
  }

  public ComplexNumber minus(ComplexNumber other) {
     return new ComplexNumber(this.real - other.real, this.imaginary - other.imaginary);
  }

  // ... other methods
}

因此,让我们来看一下此类的一些有趣的事情。 您会注意到的第一件事是,我们遵守使其成为最终类和最终成员变量的规则。 您还将注意到缺少某些东西,即变异子。 也许最有趣的是我们的加和减去方法,我们返回一个新的实例复数而不是改变现有状态。 当您第一次看到这种功能性方法时,有时可能看起来很奇怪。 我们还可以看到这些方法被命名为介词(加) 代替动词(加)。 尽管不是必须的,但单词选择的这种差异可以帮助班级用户理解他们将要接收新对象。

现在,让我们继续探讨使用不变性会带来什么好处。

  • 不可变的对象很简单:您的对象只能处于一种状态。 这样可以大大简化对象的处理。不可变对象本质上是线程安全的:没有办法破坏线程间的状态。 到目前为止,不可变对象是实现线程安全的最简单方法。不变的对象可以自由共享:由于状态无法更改,因此无需担心共享不可变对象。 如果您的对象代表一个小部件现在它仍然代表着小部件将来也是如此。 这意味着我们不需要制作防御性副本。 这还允许您缓存常用的对象,并在每次请求它们时返回它们(可能使用静态工厂)。 这可以加快对象的创建速度,并减少内存压力。您不仅可以自由共享对象,而且还可以内部共享:这似乎更像是一个利基项目,但确实很有趣。 因为状态不变,所以您可以在不同对象之间共享内部状态。 本书给出的示例是大整数对象有一个符号位来表示它代表正数还是负数。 如果您想否定对象,则只需创建一个新对象即可。大整数将符号位翻转,然后引用原始对象的其余状态。

因此,不可变对象有很多好处。 不利因素是什么,我们如何减轻这些不利因素。

更改对象中的任何内容都需要创建一个新对象:创建许多新对象只是为了改变一点点的状态可能会很昂贵,尤其是在对象很大的情况下。 如果有多个步骤来改变状态,这会变得更糟,因为这将导致创建许多可能昂贵的对象。

那么我们如何减轻这种情况呢? 如果用户可能要对您的对象执行一些常规操作,则可以为他们处理多步过程。 如果您提前知道用户将要执行哪种操作,这将非常有用。 如果不这样做怎么办? 使用此方法的另一个选择是创建一个可变的伴随类,用户可以在其上执行突变,然后可以使用它来创建不可变类。 一个例子是串Builder类及其有效创建的能力串对象。

让我们讨论一些最后的事情。

使类最终化的一种替代方法是创建私有构造函数,而是依靠静态工厂来创建不可变对象。 这为您将来提供了选择以类的子类,并为以后的性能进行优化提供了选择。

要记住的另一件事是,尽管上面我们提到状态不能改变,但是只有在外部面对状态无法改变。 这意味着只要返回的值一致,我们就可以在内部缓存数据。

一如既往,我想提一下龙目岛可以帮助我们实现目标。 不可变的对象没有什么不同。龙目岛包括一个@值您在课堂上添加的注释将使您的课堂最后,创建一个将您所有private 最后成员变量,不会生成设置器,还会为您生成许多其他样板项目(hashCode,等于,toString). While just adding this annotation won't magically make your class immutable,it will get you well on your way with taking care of the boilerplate of the class in an immutable compatible manner.

最后一个想法是始终创建不可变对象,除非有理由不这样做或您不能这样做。 即使您不能使对象完全不变,也应尝试使其尽可能不变。

那里有。 不可变的对象。 它们确实使事情变得更简单,并且可以使我们的代码更易于使用。

from: https://dev.to//kylec32/effective-java-tuesday-minimize-mutability-55db

发布了0 篇原创文章 · 获赞 0 · 访问量 405

猜你喜欢

转载自blog.csdn.net/cunxiedian8614/article/details/105690118
今日推荐