Возможно ли для протоколов ввести новое состояние в существующие классы? - PullRequest
5 голосов
/ 19 апреля 2011

Я понимаю, как протоколы могут использоваться для представления нового поведения существующим классам, но возможно ли для них (или любого другого механизма Clojure) представить состояние существующим классам? Более конкретно, я хотел бы иметь возможность связать карту с экземплярами класса, который поступает из сторонней библиотеки.

Ответы [ 4 ]

3 голосов
/ 19 апреля 2011

Протоколы концептуально схожи в интерфейсах Java в том, что они вообще не касаются состояния или представления, поэтому я почти уверен, что вы не сможете сделать это таким образом, если не сохраните состояние вне самого объекта.Однако вы можете использовать различные другие способы расширения (подкласса) классов в Clojure, чтобы сделать это, например, используя proxy или gen-class.(см. http://clojure.org/java_interop#Java%20Interop-Implementing%20Interfaces%20and%20Extending%20Classes)

2 голосов
/ 19 апреля 2011

Прежде всего, протоколы являются определениями интерфейса, и, как правило, вы не хотите указывать состояние в интерфейсе.Как правило, вы хотите поместить состояние в реализацию интерфейса, см. Ниже.

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

Неизменяемый пример из http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/reify

 (str (let [f "foo"] 
      (reify Object 
        (toString [this] f))))

Обратите внимание, что f здесь может быть ref или var или atom вместо строки, если вы хотите изменяемое состояние.

РЕДАКТИРОВАТЬ: как отмечено в комментариях, я, возможно, не сделал это полностью ясно: вы можетеиспользуйте defprotocol для определения интерфейса на основе функций, а затем используйте reify для создания экземпляров этого протокола для захвата состояния.

РЕДАКТИРОВАТЬ 2: Извините за то, что я запутался.Этот код на самом деле не будет работать для существующих классов, потому что reify не поддерживает его.Прокси, вероятно, работает как альтернатива, хотя в документации не указано, что имена функций в карте протокола 1-1 соответствуют интерфейсным методам.

2 голосов
/ 19 апреля 2011

Вы можете создать протокол с функциями set-state и get-state.Затем распространите их на нужные вам классы с помощью реализации, построенной на некотором хэш-карте.Вы не можете хранить состояние в сторонних объектах, но вы можете сделать так, чтобы ваши функции совместно использовали ссылку на хеш-таблицу с ключом объекта.Я думаю, что это решение может иметь ряд проблем, например, как вы обнаружите, когда объект будет GCed и его состояние также необходимо очистить?Вы можете использовать WeakReference или что-то еще, но это не тривиально.

0 голосов
/ 19 апреля 2011

Вы можете хранить состояние.Вам просто нужно использовать атом или ссылку и ссылку и разыменовать этот атом или ссылку в ваших методах get и set

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...