Неизменность - это ценности, а ценности - факты. Нечто имеет значение, если оно не изменится, потому что если что-то можно изменить, это означает, что с ним нельзя связать какое-либо конкретное значение. Объект был инициализирован с состоянием A и во время выполнения программы был преобразован в состояние B и состояние C. Это означает, что объект не представляет отдельное конкретное значение, а представляет собой только контейнер, абстракцию на месте в памяти, и ничего более. Вы не можете доверять такому контейнеру, вы не можете поверить, что этот контейнер имеет значение, которое, как вы полагаете, должно иметь.
Перейдем к примеру - давайте представим, что в коде создается экземпляр класса Book.
Book bookPotter = new Book();
bookPotter.setAuthor('J.K Rowling');
bookPotter.setTitle('Harry Potter');
В этом экземпляре есть несколько полей, таких как автор и заголовок. Все хорошо, но в какой-то части кода снова используются сеттеры.
Book bookLor = bookPotter; // only reference pass
bookLor.setAuthor('J.R.R Tolkien');
bookLor.setTitle('Lords of The Rings');
Не обманывайтесь разными именами переменных, на самом деле это один и тот же экземпляр. Код снова использует сеттеры на том же экземпляре. Это означает, что bookPotter никогда не был книгой о Гарри Поттере, а bookPotter - только указатель на место, где находится неизвестная книга. Тем не менее, похоже, что это больше полка, чем книга. Какое доверие вы можете иметь к такому объекту? Это книга о Гарри Поттере или книга о LoR или нет?
Изменяемый экземпляр класса - это только указатель на неизвестное состояние с характеристиками класса.
Как тогда избежать мутации? Это довольно просто в правилах:
- создание объекта с требуемым состоянием через конструктор или конструктор
- не создавать сеттеры для инкапсулированного состояния объекта
- не изменять никакое инкапсулированное состояние объекта ни в одном из его методов
Эти несколько правил позволят иметь более предсказуемые и более надежные объекты. Вернемся к нашему примеру и закажем следующие правила:
Book bookPotter = new Book('J.K Rowling', 'Harry Potter');
Book bookLor = new Book('J.R.R Tolkien', 'Lord of The Rings');
Все устанавливается на этапе конструирования, в данном случае конструктора, но для больших структур это может быть компоновщик. В объектах нет сеттеров, книга не может мутировать в другой. В таком случае bookPotter представляет ценность книги о Гарри Поттере, и вы можете быть уверены, что это неизменный факт.
Если вы заинтересованы в более широкой области неизменяемости, в этой средней статье больше о предмете по отношению к JavaScript - https://medium.com/@macsikora/the-state-of-immutability-169d2cd11310.