Clojure объекты и функции высшего порядка для инкапсуляции - PullRequest
2 голосов
/ 15 мая 2011

Это продолжение моего более раннего вопроса .

Я придумал причудливую схему объекта из моего чтения Let Over Lambda и могу думатьиз нет преимуществ по сравнению с протоколами, но хочу получить мнение.Я просто изучаю использование функций и инкапсуляции высшего порядка.

(defn new-person
  "Construct a new Person object and return a Map of accessor methods."
  [init-first-name init-last-name init-age]
  (let [first-name (ref init-first-name)
        last-name (ref init-last-name)
        age (ref init-age)]
    {:get-first-name #(@first-name)
     :set-first-name #(dosync (ref-set first-name %1))
     :get-last-name #(@last-name)
     :set-last-name #(dosync (ref-set last-name %1))
     :get-age #(@age)
     :set-age #(dosync (ref-set age %1))}))

Я могу использовать объект следующим образом:

(def fred (new-person "fred" "flintstone" 42))

и получить метод доступа следующим образом:

(fred :get-age)

но я не могу понять, как вызвать метод доступа.

Созданный объект является потокобезопасным, поскольку все изменения «экземпляра» происходят в STM.

ОБНОВЛЕНИЕ : Новая и улучшенная версия:

(defn new-person
  "Construct a new Person object and return a Map of accessor methods."
  [init-first-name init-last-name init-age]
  (let [first-name (ref init-first-name)
        last-name (ref init-last-name)
        age (ref init-age)]
    {:first-name 
        (fn
          ([] @first-name)
          ([val] (dosync (ref-set first-name val))))
     :last-name
        (fn
          ([] @last-name)
          ([val] (dosync (ref-set last-name val))))
     :age
        (fn
          ([] @age)
          ([val] (dosync (ref-set age val))))}))

Ответы [ 3 ]

5 голосов
/ 15 мая 2011

Возможно, не 100% ответ на ваш вопрос, но вы попытаетесь сделать это не очень идиоматично для Clojure.«Стандартное» решение будет выглядеть примерно так:

(defrecord Person [first-name last-name age])
(def fred (Person. "fred" "flintstone" 42))
(fred :age)

Похоже, вы принудительно изменяете состояние OO в Clojure 'objects'

3 голосов
/ 15 мая 2011

Это так же, как ваш следующий вопрос, оберните форму в другой набор скобок. Когда внутренняя форма возвращает функцию, она совпадает с символом, который возвращает функцию. Правило первой формы в скобках всегда будет рассматриваться как специальная форма, макрос или функция. Вам нужно что-то вроде цитаты, чтобы предотвратить такое поведение.

user=> (fred :get-age)
#<user$new_person$fn__531 user$new_person$fn__531@c4afc4>
user=> ((fred :get-age))
42

Это так же, как

user=> (let [age-getter (fred :get-age)] (age-getter))
42
1 голос
/ 15 мая 2011

Философия Clojure НЕ заключается в инкапсуляции доступа к самим полям записи.Инкапсуляция должна происходить на более высоких уровнях, например, в наборе функций, которые работают с этими записями.См. Clojure - типы данных :

Инкапсуляция информации - это глупые поля, открытые, используйте протоколы / интерфейсы, чтобы избежать зависимостей

...