вторник, 16 мая 2017 г.

Gradients of Immutability

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



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

Константа
 
Не допускается никаких изменений в инкапсулированном объекте и всегда возвращает тот же текст (для краткости я пропустил конструкторы):
class Book {
  private final String ttl;
  Book rename(String title) {
    return new Book(title);
  }
  String title() {
    return this.ttl;
  }
}
Это то, что мы обычно имеем в виду, когда говорим о неизменяемых объектах. Такой класс очень близок к чистой функции, а это означает, что независимо от того, сколько раз мы создаем экземпляр с теми же начальными значениями, результат title () будет таким же.

Не константа
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 () - он возвращает разные значения, если мы вызываем его несколько раз с хотя бы с одноминутным интервалом. 

Объект неизменен

Это просто больше не константа.
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, реальный файл на диске был изменен. Мы можем сделать то же самое, но в памяти:
class Book {
  private final StringBuffer buffer;
  Book rename(String title) {
    this.buffer.setLength(0);
    this.buffer.append(title);
    return this;
  }
  String title() {
    return this.buffer.toString();
  }
}

Объект по-прежнему неизменен. Он потокобезопасен? Нет. Это константа? Нет. Это неизменный объект? Да. Смущенны? Держу пари, что да.

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

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

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

Если вам понравилась эта статья, вам обязательно понравятся эти очень релевантные сообщения:


В статье приводятся аргументы о том, почему классы / объекты в объектно-ориентированном программировании должны быть неизменными, т.е. Никогда не изменять их инкапсулированное состояние

Как неизменяемый объект может обладать состоянием и поведением?

Состояние и поведение объектов - две разные вещи, и сбивание с толку двух часто приводит к неправильному дизайну.

Неизменяемые объекты не являются немыми

Неизменяемые объекты - это не то же самое, что пассивные структуры данных без сеттеров, несмотря на очень распространенное заблуждение. 

Комментариев нет:

Отправить комментарий