Часто необходимо модифицировать состояние объекта, особенно когда работаешь с java библиотекой, смысл которой сводится к вызову callback'ов и необходимо сохранять промежуточное состояние между вызовами. Например SAX парсер.
Clojure определяет три способа работы с изменяемыми данными. Это ссылки, агенты и атомы. Все они описаны в статье Алексея Отта (http://alexott.net/ru/clojure/clojure-intro/).
Для моего случая подходит синхронное изменение и заворачивать обращения к изменяемым переменным в транзакции нет необходимости. Поэтому я буду использовать атомы(atoms).
Для примера опишем класс com.Example. Объявим одновременно пространство имен и класс(com.Example) с помощью макроса ns.
:init - имя конструктора
:state - имя атрибута для хранения состояния объекта
:constructors - описание типов параметров конструкторов класса
:methods - описание доступных методов класса, в формате [имя [тип_параметра ...] тип_возвращаемого_значения]
:main - false - не генерировать, автоматически, метод main(первый метод который будет вызван для java программы)
Теперь код объявленных выше методов.
Конструктор:
конструктор без параметров. Конструктор класса в clojure должен вернуть вектор с двумя элементами.
Первый элемент - еще один вектор, содержит параметры конструктора родительского класса([] - для родительского конструктора без параметров). Второй элемент - значение переменной состояния(имя которой определяется через параметр :state). В нашем случае это хеш(maps). Применение функции atoms делает состояние объекта изменяемым.
После того как state в классе объявлен как изменяемый его можно модифицировать функцией swap!.
Атрибуты объекта будут хранится как ключевые слова(keywords) а значения - это целые числа.
Методы для сохранения и получения значения атрибутов объекта будут такими:
Clojure определяет три способа работы с изменяемыми данными. Это ссылки, агенты и атомы. Все они описаны в статье Алексея Отта (http://alexott.net/ru/clojure/clojure-intro/).
Для моего случая подходит синхронное изменение и заворачивать обращения к изменяемым переменным в транзакции нет необходимости. Поэтому я буду использовать атомы(atoms).
Для примера опишем класс com.Example. Объявим одновременно пространство имен и класс(com.Example) с помощью макроса ns.
(ns com.Example (:gen-class :state state :init init :constructors {[] []} :methods [[setAttr [clojure.lang.Keyword int] void], [getAttr [clojure.lang.Keyword] int], [removeAttr [clojure.lang.Keyword] void]] :main false))
:init - имя конструктора
:state - имя атрибута для хранения состояния объекта
:constructors - описание типов параметров конструкторов класса
:methods - описание доступных методов класса, в формате [имя [тип_параметра ...] тип_возвращаемого_значения]
:main - false - не генерировать, автоматически, метод main(первый метод который будет вызван для java программы)
Теперь код объявленных выше методов.
Конструктор:
(defn -init []
[[] (atom {})])
конструктор без параметров. Конструктор класса в clojure должен вернуть вектор с двумя элементами.
[ [superclass-constructor-args] state]
Первый элемент - еще один вектор, содержит параметры конструктора родительского класса([] - для родительского конструктора без параметров). Второй элемент - значение переменной состояния(имя которой определяется через параметр :state). В нашем случае это хеш(maps). Применение функции atoms делает состояние объекта изменяемым.
После того как state в классе объявлен как изменяемый его можно модифицировать функцией swap!.
Атрибуты объекта будут хранится как ключевые слова(keywords) а значения - это целые числа.
Методы для сохранения и получения значения атрибутов объекта будут такими:
(defn -setAttr [this attr value] (swap! (.state this) assoc attr value)) (defn -getAttr [this attr] (get @(.state this) attr)) (defn -removeAttr [this attr] (swap! (.state this) dissoc attr))
И маленький пример использования
user=> (def ex (com.Example.))
#'user/ex
user=> (.state ex)
#<Atom@724eb043: {}>
user=> ex
#<Example com.Example@30c06258>
user=> (.setAttr ex :a 1)
nil
user=> (.setAttr ex :b 2)
nil
user=> (.setAttr ex :super-key -9)
nil
user=> (.state ex)
#<Atom@724eb043: {:super-key -9, :b 2, :a 1}>
user=> (.getAttr ex :b)
2
user=> (.removeAttr ex :super-key)
nil
user=> (.state ex)
#<Atom@724eb043: {:b 2, :a 1}>
Комментариев нет:
Отправить комментарий