Создание библиотеки протоколов и defrecords для использования из Java
На данный момент у меня есть полностью функциональная библиотека Clojure, которая вызывается из Java.
Способ, которым я делаю это: у меня есть файл, который использует gen-class, чтобы обернуть весь API как статические методы одного класса и передавать и выводить данные в форме IPersistentVector и IPersistentMap.
Однако сейчас я делаю рефакторинг библиотеки и помещаю функциональность в разные протоколы.
У меня есть четыре протокола, давайте назовем их A, B, C и D. И два defrecords, X и Y. X и Y оба реализуют протоколы A, B и C. В то время как Y также реализует D.
Что мне нужно сделать, чтобы сделать их доступными для Java? Доступны ли они автоматически как интерфейсы и классы? Или я все еще должен сделать эквивалент gen-класса, чтобы сделать их публичными?
Если нет, что эквивалентно предложению gen-class: Methods, где я определяю типы Java для аргументов методов?
У кого-нибудь есть простой пример того, как сделать протоколы и записи доступными для Java?
1 ответ
defprotocol
Каждый протокол Clojure также является интерфейсом Java с тем же именем и методами. Если я возьму пример из IBM DeveloperWorks, мы увидим, что:
(ns com.amalgamated)
(defprotocol Fulfillment
(invoice [this] "Returns an invoice")
(manifest [this] "Returns a shipping manifest"))
Эквивалентно:
package com.amalgamated;
public interface Fulfillment {
public Object invoice();
public Object manifest();
}
Clojure.org также имеет некоторую (довольно краткую) информацию об этом.
Клиент Java, желающий участвовать в протоколе, может сделать это наиболее эффективно, реализовав сгенерированный протоколом интерфейс. Внешние реализации протокола (которые необходимы, когда вы хотите, чтобы класс или тип не находились в вашем контроле для участия в протоколе) могут быть предоставлены с использованием конструкции extends:
(extend AType AProtocol {:foo an-existing-fn :bar (fn [a b] ...) :baz (fn ([a]...) ([a b] ...)...)} BProtocol {...} ...)
definterface
Если вы стремитесь к производительности, вы можете рассмотреть возможность использования definterface
, использование которого аналогично протоколам. Этот пост также содержит подробную информацию о том, как его использовать:
(definterface Foo
[^int foo [x ^String y]]
[^void bar [^ints is]])
definterface
кажется, быстрее, чем протоколы.
defrecord
Так же, record
с (а также deftype
а также definterface
) будет генерировать классы Java. Опять же, http://clojure.org/datatypes имеет полезную информацию (выделено мое):
deftype и defrecord динамически генерируют скомпилированный байт-код для именованного класса с набором заданных полей и, необязательно, методов для одного или нескольких протоколов и / или интерфейсов. Они подходят для динамической и интерактивной разработки, не требуют компиляции AOT и могут быть переоценены в течение одного сеанса. Они похожи на defstruct при создании структур данных с именованными полями, но отличаются от defstruct тем, что: [...]
Так что да, если будет доступно с Java. Просто будьте осторожны с именами.
Как примечание, вы можете взглянуть на вызов Clojure из Java.