创建一个Protocols和defrecords库,供Java使用

时间:2015-08-30 14:35:33

标签: clojure clojure-java-interop clojure-protocol

目前,我有一个功能齐全的Clojure库,可以从Java调用。

我这样做:我有一个文件,它使用gen-class将整个API包装为单个类的静态方法,并以IPersistentVector和IPersistentMap的形式传入和传出数据。

然而,现在,我正在重构库并将功能置于各种协议之后。

我有四个协议,我们称之为A,B,C和D.两个defrecords,X和Y.X和Y都实现协议A,B和C.而Y也实现D。

我需要做些什么才能将这些内容提供给Java?这些是否自动作为接口和类?或者我仍然必须做相当于gen-class的公开?

如果没有,gen-class:methods子句的等价物是什么,我在哪里定义方法参数的Java类型?

有没有人有一个简单的例子可以让Java协议和记录可用?

1 个答案:

答案 0 :(得分:6)

defprotocol

每个Clojure协议也是具有相同名称和方法的Java接口。如果我从ibm developerworks中提取示例,我们会看到:

override func viewDidLoad() {
    super.viewDidLoad()

    let button   = UIButton.buttonWithType(UIButtonType.System) as UIButton
    button.frame = CGRectMake(100, 100, 100, 50)
    button.backgroundColor = UIColor.greenColor()
    button.setTitle("Test Button", forState: UIControlState.Normal)
    button.addTarget(self, action: "buttonAction:", forControlEvents:UIControlEvents.TouchUpInside)

    self.view.addSubview(button)
}  

func buttonAction(sender:UIButton!) {
    println("Button tapped") {
}

相当于:

(ns com.amalgamated)

(defprotocol Fulfillment
  (invoice [this] "Returns an invoice")
  (manifest [this] "Returns a shipping manifest"))

Clojure.org也有一些(相当简洁的)信息。

  

希望参与协议的Java客户端最多可以这样做   通过实现协议生成的接口有效地实现。外部   协议的实现(当你想要一个时需要它   类或类型不在您的控制中参与协议)可以   使用extend构造提供:

package com.amalgamated;

public interface Fulfillment {
    public Object invoice();
    public Object manifest();
}

definterface

如果您的目标是性能,可以考虑使用(extend AType AProtocol {:foo an-existing-fn :bar (fn [a b] ...) :baz (fn ([a]...) ([a b] ...)...)} BProtocol {...} ...) ,其使用类似于协议。此SO post还包含有关如何使用它的详细信息:

definterface

(definterface Foo [^int foo [x ^String y]] [^void bar [^ints is]]) 似乎比协议faster

defrecord

同样,definterface(以及recorddeftype)将生成Java类。 同样,Clojure.org/datatypes提供了有用的信息(强调我的):

  

deftype和 defrecord 动态生成a的编译字节码   带有一组给定字段的命名类,以及可选的方法   一个或多个协议和/或接口。它们适合动态   和交互式开发,无需进行AOT编译,并且可以   在单个会话过程中重新评估。它们类似于   defstruct生成具有命名字段的数据结构,但不同   来自defstruct:[...]

所以是的,如果可以从Java获得。 注意命名。

作为旁注,您可能需要查看calling Clojure from Java