Gradients of Immutability

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

Хорошие объекты неизменяемы, но не обязательно являются константами. Я пытался объяснить это здесь, здесь и здесь, но теперь настало время для еще одной попытки. На самом деле, чем больше я об этом думаю, тем больше я понимаю, что неизменяемость не является абсолютной - есть несколько оттенков, давайте посмотрим.

Как мы согласовали здесь, объект является представителем кого-то еще (какой-либо сущности или сущностей, других объектов, данных, памяти, файлов и т.п.). Давайте рассмотрим несколько объектов, которые выглядят одинаково для нас, но представляют разные вещи, затем проанализируем, насколько они неизменяемы и почему.

Это константа; она не позволяет вносить изменения в инкапсулированный объект и всегда возвращает один и тот же текст (я опустил конструкторы для краткости).

Это то, о чем мы обычно говорим, когда речь идет о неизменяемых объектах. Такой класс очень близок к чистой функции, что означает, что несмотря на то, сколько раз мы создаем его с одинаковыми начальными значениями, результат title() будет всегда одинаковым.

Check out this one:

class Book {
  private final String ttl;
  Book rename(String title) {
    return new Book(title);
  }
  String title() {
    return String.format(
      "%s (as of %tR)", this.ttl, new Date()
    );
  }
}

Объект по-прежнему является неизменным, но уже не является чистой функцией из-за метода title(), который возвращает разные значения при вызове несколько раз с интервалом в минуту. Объект неизменяемый, просто уже не является константой.

How about this one:

class Book {
  private final Path path;
  Book rename(String title) {
    Files.write(
      this.path,
      title.getBytes(),
      StandardOpenOption.CREATE
    );
    return this;
  }
  String title() {
    return new String(
      Files.readAllBytes(this.path)
    );
  }
}

Этот неизменяемый объект хранит название книги в файле. Он не является константой, потому что его метод title() может возвращать разные значения при каждом втором вызове. Более того, представленная сущность (файл) не является константой. Мы не можем сказать, является ли она изменяемой или неизменяемой, так как мы не знаем, как реализован метод Files.write(). Но мы точно знаем, что это не константа, потому что он принимает запросы на изменение.

Неизменяемый объект может не только представлять, но даже инкапсулировать изменяемый объект. Как и в предыдущем примере, изменяемый файл был инкапсулирован. Несмотря на то, что он был представлен неизменяемым классом Path, реальный файл на диске был изменяемым. Мы можем сделать то же самое, но в памяти:

Объект все еще неизменяемый. Он является потокобезопасным? Нет. Является ли он константой? Нет. Является ли он неизменяемым? Да. Запутано? Конечно.

Моя точка зрения состоит в том, что неизменяемость не является бинарной; существует множество её форм. Самая простая из них, конечно, - константа. Константы практически то же самое, что и чистые функции в функциональном программировании. Но объектно-ориентированное программирование позволяет нам сделать несколько шагов вперед и дать неизменяемым объектам больше разрешений и гибкости. В ООП у нас может быть гораздо больше форм неизменяемости.

Общим для всех этих примеров является то, что наши объекты преданы сущностям, которые они инкапсулируют. Нет сеттеров, которые могли бы их изменить. Все инкапсулированные объекты являются final.

Это единственное качество, которое отличает изменяемые объекты от неизменяемых. Последние всегда преданы сущностям, которые они инкапсулируют и представляют. Что касается всего остального … это зависит.

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-11-17 at 17:09

sixnines availability badge   GitHub stars