Ответ 1
Перефразируя вопрос:
Возможно ли автоматическое обновление всех связанных объектов при изменении одного объекта в неизменяемой коллекции?
Короткий ответ
Нет.
Длинный ответ
Нет, но ничего не меняется в неизменяемой структуре данных, так что это не проблема.
Более длинный ответ
Это сложнее...
Неизменность
Весь смысл неизменяемых объектов заключается в том, что если у вас есть ссылка на неизменяемый объект, вам никогда не придется проверять, изменилось ли какое-либо его свойство. Итак, это не проблема? Ну...
Последствия
Есть некоторые последствия этого: хорошие или плохие ли они зависят от ваших ожиданий:
- Нет никакой разницы между pass-by-value и pass-by-reference семантика
- Некоторые сравнения могут быть проще
- Когда вы передаете ссылку на объект где-то, вам не нужно беспокоиться о том, что какая-то другая часть кода изменит его.
- Когда вы получаете ссылку на объект откуда-то, вы знаете, что он никогда не изменится.
- Вы избегаете некоторых проблем с concurrency, потому что нет понятия изменения времени
- Когда ничего не меняется, вам не нужно беспокоиться, являются ли изменения атомарными
- Проще реализовать транзакционную память программного обеспечения (STM) с неизменяемыми структурами данных
Но мир изменен
Конечно, на практике мы часто имеем дело со значениями, которые меняются во времени. Может показаться, что неизменяемое состояние не может описывать изменчивый мир, но есть некоторые способы, с которыми люди справляются с этим.
Посмотрите на это так: если у вас есть свой адрес на каком-то ID, и вы переходите на другой адрес, этот идентификатор должен быть изменен, чтобы соответствовать новым истинным данным, потому что уже не так, что вы живете по этому адресу, Но когда вы получаете счет-фактуру, когда вы покупаете что-то, что содержит ваш адрес, а затем вы меняете свой адрес, счет-фактура остается прежним, поскольку по-прежнему верно, что вы проживали по этому адресу, когда был составлен счет-фактура. Некоторые представления данных в реальном мире неизменяемы, например, счета-фактуры в этом примере, а некоторые являются изменяемыми, как идентификаторы.
Теперь, взяв ваш пример, если вы решите использовать неизменяемые структуры для моделирования своих данных, вы должны подумать об этом так, как вы думаете о счете-фактуре из моего примера. Возможно, данные не обновлены, но в какой-то момент времени они всегда будут согласованными и истинными, и они никогда не изменятся.
Как справиться с изменением
Итак, как моделировать изменение с неизменяемыми данными? Существует хороший способ, который был решен в Clojure с помощью Vars, Refs, Atoms и Agents и ClojureScript (компилятор для Clojure, который нацелен на JavaScript) поддерживает некоторые из них (в частности, Atoms должны работать как в Clojure, но нет ссылок, STM, Vars или агентов - см. каковы различия между ClojureScript и Clojure в отношении concurrency функций).
Рассматривая как Atoms реализованы в ClojureScript, кажется, что вы можете просто использовать обычные объекты JavaScript для достижения того же. Он будет работать для таких вещей, как наличие объекта JavaScript, который сам изменяет, но имеет свойство, которое является ссылкой на неизменяемый объект - вы не сможете изменить какие-либо свойства этого неизменяемого объекта, но вы сможете построить другой неизменяемый объект, и замените старый на новый в своем изменчивом объекте верхнего уровня.
Другие языки, такие как Haskell, которые чисто функциональные могут иметь разные способы борьбы с изменчивым миром, например, monads (концепция, которую трудно объяснить), Дуглас Крокфорд, автор JavaScript: Хорошие части и первооткрыватель JSON приписывает его "монадическое проклятие" в его речи Монады и Гондады).
Ваш вопрос кажется простым, но проблема, с которой он сталкивается, на самом деле довольно сложная. Разумеется, было бы не просто ответить "Нет" на ваш вопрос, можно ли автоматически обновлять все связанные объекты при изменении одного объекта, но это сложнее, чем это, и говорить, что в неизменяемых объектах ничего не меняется ( поэтому эта проблема никогда не произойдет) будет также бесполезной.
Возможные решения
У вас может быть объект или переменная верхнего уровня, из которой вы всегда получаете доступ ко всем вашим структурам. Скажем, у вас есть:
var data = { value: Immutable.Map({...}) }
Если вы всегда получаете доступ к своим данным с помощью data.value
(или с некоторыми более лучшими именами), вы можете передать data
в какую-либо другую часть вашего кода, и всякий раз, когда ваше состояние изменяется, вы можете просто назначить новую Immutable.Map({...}) к вашему data.value
, и в этот момент весь ваш код, который использует data
, получит свежие значения.
Как и когда обновить data.value
до новой неизменяемой структуры может быть решена путем автоматического ее запуска из ваших функций сеттера, которые вы будете использовать для обновления вашего состояния.
Другим способом было бы использовать подобные трюки на уровне каждой структуры, например - я использую оригинальное написание переменных:
var parent = {data: Immutable.Map({name: 'John'}) };
var childrens = {data: Immutable.List([
Immutable.Map({name: 'Alice', parent: parent}),
Immutable.Map({name: 'Bob', parent: parent})
])};
но тогда вы должны помнить, что то, что вы имеете в качестве значений, не является неизменяемыми структурами, а скорее дополнительными объектами со ссылками на неизменяемые структуры, которые вводят дополнительный уровень косвенности.
Некоторое чтение
Я бы предложил посмотреть некоторые из этих проектов и статей:
- Неизменяемое действие статьи Peter Hausel
- Morearty.js - использование неизменяемого состояния в React как в Om, но написанный в чистом JavaScript
- react-cursor - абстракция функционального управления состоянием для использования с Facebook
- Omniscient - библиотека, предоставляющая абстракцию для компонентов React, которая позволяет быстро рендерить сверху вниз неизменяемые данные * Om - Интерфейс ClojureScript для реагирования
- mori - библиотека для использования постоянных структур данных ClojureScript в JavaScript
- Fluxy - реализация архитектуры Facebook Flux
- Facebook Immutable - постоянные коллекции данных для JavaScript, которые в сочетании с Facebook React и Facebook Flux сталкивается с аналогичными проблемами, которые у вас есть (поиск того, как объединить Immutable с React and Flux, может дать вам некоторые хорошие идеи)
Я надеюсь, что этот ответ, даже если не даст простого решения, тем не менее будет полезен, потому что описание изменчивого мира с неизменяемыми структурами - очень интересная и важная проблема.
Другие подходы
Для другого подхода к неизменяемости, с неизменяемыми объектами, которые являются прокси-данными для данных, которые необязательно являются постоянными, см. Неизменяемые объекты против общего смысла вебинар Егора Бугаенко и его статьи:
- Объекты должны быть неизменными
- Как невосприимчивость помогает
- Как неизменяемый объект может иметь состояние и поведение?
- Неизменяемые объекты не тупые
Егор Бугаенко использует термин "неизменный" в несколько ином смысле, чем то, что обычно означает в контексте функционального программирования. Вместо использования неизменных или постоянных структур данных и функционального программирования он выступает за использование объектно-ориентированного программирования в первоначальном смысле этого слова так, что вы никогда не мутируете какой-либо объект, но можете попросить его изменить какое-либо состояние или изменить некоторые данные, которые сами по себе считаются отдельными от объекта. Легко представить непреложный объект, который говорит с реляционной базой данных. Сам объект может быть неизменным, но он может обновлять данные, хранящиеся в базе данных. Несколько сложнее представить, что некоторые данные, хранящиеся в ОЗУ, можно рассматривать как одинаково отдельно от объекта как данные в базе данных, но на самом деле нет большой разницы. Если вы думаете об объектах как автономных объектах, которые выставляют какое-то поведение, и вы уважаете их границы абстракции, тогда на самом деле имеет смысл думать о объектах как нечто отличное от просто данных, а затем вы можете иметь неизменяемые объекты с изменяемыми данными.
Прокомментируйте, если что-то нуждается в уточнении.