Неизменность и совместно использованные ссылки - как согласовать?

Рассмотрите этот упрощенный домен приложения:

  • Преступная база данных Investigative
  • Person любой вовлеченный в расследование
  • Report немного информации, которая является частью расследования
  • A Report ссылается на основное устройство Person (предмет расследования)
  • A Report имеет сообщников, которые во вторую очередь связаны (и могло, конечно, быть основным в других расследованиях или отчетах
  • Эти классы имеют идентификаторы, которые используются для хранения их в базе данных, так как их информация может изменяться со временем (например, мы могли бы найти новые псевдонимы для человека или добавить фигурантов уголовного дела к отчету),

Доменный http://yuml.me/13fc6da0

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

Если я изменяю некоторые метаданные о a Person. Начиная с моего Person неизменные объекты, у меня мог бы быть некоторый код как:

class Person(
    val id:UUID,
    val aliases:List[String],
    val reports:List[Report]) {

  def addAlias(name:String) = new Person(id,name :: aliases,reports)
}

Так, чтобы мой Person с новым псевдонимом становится новым объектом, также неизменным. Если a Report относится к тому человеку, но псевдоним был изменен в другом месте в системе, моем Report теперь относится к "старому" человеку, т.е. человеку без нового псевдонима.

Точно так же я мог бы иметь:

class Report(val id:UUID, val content:String) {
  /** Adding more info to our report */
  def updateContent(newContent:String) = new Report(id,newContent)
}

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

Это могло быть сделано при наличии всех объектов "обновление" от центрального хранилища данных и всех операций, которые создают новый, обновленный, хранилище объектов к центральному хранилищу данных, но это чувствует себя подобно дрянному переопределению ссылки базового языка. т.е. это было бы более ясно просто сделать эти "вторичные storable объекты" изменяемыми. Так, если я добавляю псевдоним к a Person, все ссылающиеся домены видят новое значение, ничего не делая.

Как с этим имеют дело с тем, когда мы хотим избежать переменчивости, или действительно ли это - случай, где неизменность не полезна?

10
задан davetron5000 8 April 2010 в 22:07
поделиться

3 ответа

Если X относится к Y, оба неизменяемы, а Y изменяется (т.е. вы заменяете его обновленной копией), тогда у вас нет другого выбора, кроме как заменить X также (потому что он изменился, поскольку новый X указывает на новый Y, а не на старый).

Это быстро становится головной болью при поддержке сильно взаимосвязанных структур данных. У вас есть три общих подхода.

  • Забудьте о неизменности вообще. Сделайте ссылки изменяемыми. При необходимости исправьте их. Убедитесь, что вы действительно их исправили, иначе вы можете получить утечку памяти (X относится к старому Y, который относится к старому X, который относится к более старому Y и т. Д.).
  • Не храните прямые ссылки, а скорее идентификационные коды, которые вы можете найти (например, ключ в хэш-карте). Затем вам нужно обработать случай сбоя поиска, но в остальном все довольно надежно. Это, конечно, немного медленнее, чем прямая ссылка.
  • Измените весь мир. Если что-то изменилось, все, что связано с этим, также должно быть изменено (и выполнение этой операции одновременно со сложным набором данных сложно, но теоретически возможно, или, по крайней мере, изменяемые аспекты этого могут быть скрыты, например, с большим количеством ленивых значений) .

Я полагаю, что предпочтительнее, зависит от вашей скорости поиска и обновлений.

10
ответ дан 3 December 2019 в 20:40
поделиться

Я думаю, вы пытаетесь квадрат круга. Person является неизменным, список отчетов о человеке является частью Person, и список отчетов может изменяться.

Может ли неизменяемый объект Person иметь ссылку на изменяемый объект PersonRecord, в котором хранятся такие вещи, как отчеты и псевдонимы?

3
ответ дан 3 December 2019 в 20:40
поделиться

Я предлагаю вам прочитать, как люди решают эту проблему в clojure и Akka. Почитайте о программной транзакционной памяти. И некоторые мои мысли...

Неизменность существует не ради самой себя. Неизменность - это абстракция. Она не "существует" в природе. Мир изменчив, мир постоянно меняется. Поэтому вполне естественно, что структуры данных могут быть изменяемыми - они описывают состояние реального или моделируемого объекта в данный момент времени. И похоже, что ООП здесь рулит. На концептуальном уровне проблема с таким отношением заключается в том, что объект в оперативной памяти = реальный объект - данные могут быть неточными, они приходят с задержкой и т.д.

Поэтому в случае самых тривиальных требований вы можете обойтись всем мутабельным - лицами, отчетами и т.д. Практические проблемы возникнут, когда:

  1. структуры данных изменяются из параллельных потоков
  2. пользователи предоставляют противоречивые изменения для одних и тех же объектов
  3. пользователь предоставляет некорректные данные и их нужно откатить

С наивной мутабельной моделью вы быстро закончите с несогласованными данными и разрушающейся системой. Мутабельность подвержена ошибкам, а неизменяемость невозможна. Вам нужен транзакционный взгляд на мир. В рамках транзакции программа видит неизменяемый мир. А STM управляет изменениями, чтобы применить их последовательным и потокобезопасным способом.

5
ответ дан 3 December 2019 в 20:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: