2013-02-12 1 views
4

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

Таким образом, экземпляр X может указывать на экземпляр Y и наоборот.

В классах Clojure обычно переводит на карты, чтобы мы могли иметь:

{:type :x :name "instance of X"} 
{:type :y :name "instance of Y"} 

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

ответ

4

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

{:type :x 
:name "instance of X" 
:y {:type :y 
    :name "instance of Y"}} 

На самом деле, это настолько часто, что clojure.core обеспечивает основные функции, такие как get-inassoc-in, и update-in для облегчения работы с такими структурами.

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

Путь я обычно видел это рассматривается, чтобы ввести слой косвенности, используя atom:

(def x {:type :x, :name "x instance", :y (atom nil)}) 
(def y {:type :y, :name "y instance", :x (atom nil)}) 
(set! *print-level* 3) ;; do this in the REPL to avoid stack overflow 
         ;; when printing the results of the following calls 
(reset! (:y x) y) 
(reset! (:x y) x) 
+0

не рефов быть больше подходит для этого, так как их изменение может быть скоординированы? –

+0

btw, этот код приводит к «StackOverflowError clojure.lang.RT.toArray (RT.java:1544)», когда я попробовал его –

+0

Зависит от приложения. Если вы просто хотите установить значение один раз при создании карты, возможно, достаточно атома. Если вы собираетесь делать много обновлений и хотите обеспечить согласованность графика, то да, вы, вероятно, должны использовать refs. Переполнение стека, вероятно, связано с печатью результата, так как печать атома покажет его значение - не уверен, повлияет ли это '* print-level *' на это или нет. – Alex

Смежные вопросы