Создание библиотеки протоколов и 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.

Другие вопросы по тегам